#include "TStreamerInfo.h"
#include "TFile.h"
#include "TROOT.h"
#include "TClonesArray.h"
#include "TStreamerElement.h"
#include "TClass.h"
#include "TClassEdit.h"
#include "TDataMember.h"
#include "TMethodCall.h"
#include "TDataType.h"
#include "TRealData.h"
#include "TBaseClass.h"
#include "TBuffer.h"
#include "TArrayC.h"
#include "TArrayI.h"
#include "TArrayF.h"
#include "TArrayD.h"
#include "TArrayS.h"
#include "TArrayL.h"
#include "TError.h"
#include "TRef.h"
#include "TProcessID.h"
#include "TSystem.h"
#include "TStreamer.h"
#include "TContainerConverters.h"
#include "TCollectionProxyFactory.h"
#include "TVirtualCollectionProxy.h"
#include "TInterpreter.h"
#include "TMemberInspector.h"
#include "TMakeProject.h"
#include "TSchemaRuleSet.h"
#include "TSchemaRule.h"
#include "TVirtualMutex.h"
#include "TStreamerInfoActions.h"
std::atomic<Int_t> TStreamerInfo::fgCount{0};
const Int_t kMaxLen = 1024;
ClassImp(TStreamerInfo)
static void R__TObjArray_InsertAt(TObjArray *arr, TObject *obj, Int_t at)
{
Int_t last = arr->GetLast();
arr->AddAtAndExpand(arr->At(last),last+1);
for(Int_t ind = last-1; ind >= at; --ind) {
arr->AddAt( arr->At(ind), ind+1);
};
arr->AddAt( obj, at);
}
static void R__TObjArray_InsertAt(TObjArray *arr, std::vector<TStreamerArtificial*> &objs, Int_t at)
{
Int_t offset = objs.size();
Int_t last = arr->GetLast();
arr->AddAtAndExpand(arr->At(last),last+offset);
for(Int_t ind = last-1; ind >= at; --ind) {
arr->AddAt( arr->At(ind), ind+offset);
};
for(size_t ins = 0; ins < objs.size(); ++ins) {
arr->AddAt(objs[ins], at+ins);
}
}
static void R__TObjArray_InsertAfter(TObjArray *arr, TObject *newobj, TObject *oldobj)
{
Int_t last = arr->GetLast();
Int_t at = 0;
while (at<last && arr->At(at) != oldobj) {
++at;
}
++at;
R__TObjArray_InsertAt(arr, newobj, at);
}
static void R__TObjArray_InsertBefore(TObjArray *arr, TObject *newobj, TObject *oldobj)
{
Int_t last = arr->GetLast();
Int_t at = 0;
while (at<last && arr->At(at) != oldobj) {
++at;
}
R__TObjArray_InsertAt(arr, newobj, at);
}
TStreamerInfo::TStreamerInfo()
{
fNumber = fgCount;
fClass = 0;
fElements = 0;
fComp = 0;
fCompFull = 0;
fCompOpt = 0;
fCheckSum = 0;
fNdata = 0;
fNfulldata= 0;
fNslots = 0;
fSize = 0;
fClassVersion = 0;
fOnFileClassVersion = 0;
fOldVersion = Class()->GetClassVersion();
fNVirtualInfoLoc = 0;
fVirtualInfoLoc = 0;
fLiveCount = 0;
fReadObjectWise = 0;
fReadMemberWise = 0;
fReadMemberWiseVecPtr = 0;
fWriteObjectWise = 0;
fWriteMemberWise = 0;
fWriteMemberWiseVecPtr = 0;
}
TStreamerInfo::TStreamerInfo(TClass *cl)
: TVirtualStreamerInfo(cl)
{
fgCount++;
fNumber = fgCount;
fClass = cl;
fElements = new TObjArray();
fComp = 0;
fCompFull = 0;
fCompOpt = 0;
fCheckSum = 0;
fNdata = 0;
fNfulldata= 0;
fNslots = 0;
fSize = 0;
fClassVersion = fClass->GetClassVersion();
fOnFileClassVersion = 0;
fOldVersion = Class()->GetClassVersion();
fNVirtualInfoLoc = 0;
fVirtualInfoLoc = 0;
fLiveCount = 0;
fReadObjectWise = 0;
fReadMemberWise = 0;
fReadMemberWiseVecPtr = 0;
fWriteObjectWise = 0;
fWriteMemberWise = 0;
fWriteMemberWiseVecPtr = 0;
}
TStreamerInfo::~TStreamerInfo()
{
delete [] fComp; fComp = 0;
delete [] fCompFull; fCompFull = 0;
delete [] fCompOpt; fCompOpt = 0;
delete [] fVirtualInfoLoc; fVirtualInfoLoc =0;
delete fReadObjectWise;
delete fReadMemberWise;
delete fReadMemberWiseVecPtr;
delete fWriteObjectWise;
delete fWriteMemberWise;
delete fWriteMemberWiseVecPtr;
if (!fElements) return;
fElements->Delete();
delete fElements; fElements=0;
}
namespace {
struct TPreventRecursiveBuildGuard {
TPreventRecursiveBuildGuard(TStreamerInfo* info): fInfo(info) {
fInfo->SetBit(TStreamerInfo::kBuildRunning);
fInfo->SetBit(TStreamerInfo::kBuildOldUsed);
}
~TPreventRecursiveBuildGuard() {
fInfo->ResetBit(TStreamerInfo::kBuildOldUsed);
fInfo->ResetBit(TStreamerInfo::kBuildRunning);
}
TStreamerInfo* fInfo;
};
}
void TStreamerInfo::Build()
{
if (fIsCompiled) return;
R__LOCKGUARD(gInterpreterMutex);
if (fIsCompiled) return;
if (fIsBuilt) return;
if (TestBit(TStreamerInfo::kBuildRunning)) return;
TPreventRecursiveBuildGuard buildGuard(this);
if (fClass->GetCollectionProxy()) {
TVirtualCollectionProxy *proxy = fClass->GetCollectionProxy();
TString title;
if (proxy->GetValueClass()) {
title.Form("<%s%s> Used to call the proper TStreamerInfo case",proxy->GetValueClass()->GetName(),proxy->HasPointers() ? "*" : "");
} else {
title .Form("<%s%s> Used to call the proper TStreamerInfo case",TDataType::GetTypeName(proxy->GetType()),proxy->HasPointers() ? "*" : "");
}
TStreamerElement* element = new TStreamerSTL("This", title.Data(), 0, fClass->GetName(), *proxy, 0);
fElements->Add(element);
Compile();
fIsBuilt = kTRUE;
return;
}
TStreamerElement::Class()->IgnoreTObjectStreamer();
fClass->BuildRealData();
fCheckSum = fClass->GetCheckSum();
Bool_t needAllocClass = kFALSE;
Bool_t wasCompiled = fComp != 0;
const ROOT::TSchemaMatch* rules = 0;
if (fClass->GetSchemaRules()) {
rules = fClass->GetSchemaRules()->FindRules(fClass->GetName(), fClassVersion);
}
bool isCollection = fClass->GetCollectionProxy();
bool isString = !strcmp(fClass->GetName(), "string");
TBaseClass* base = 0;
TIter nextb(fClass->GetListOfBases());
while ((base = (TBaseClass*)nextb())) {
TStreamerElement* element = 0;
Int_t offset = base->GetDelta();
if (offset == kMissing) {
continue;
}
if (offset == kNeedObjectForVirtualBaseClass) {
Error("Build()", "Cannot stream virtual base %s of class %s",
base->GetName(), fClass->GetName());
continue;
}
const char* bname = base->GetName();
const char* btitle = base->GetTitle();
if (!strcmp(bname, "string")) {
element = new TStreamerSTLstring(bname, btitle, offset, bname, kFALSE);
} else if (base->IsSTLContainer()) {
TVirtualCollectionProxy *proxy = base->GetClassPointer()->GetCollectionProxy();
if (proxy) element = new TStreamerSTL(bname, btitle, offset, bname, *proxy, kFALSE);
else element = new TStreamerSTL(bname, btitle, offset, bname, 0, kFALSE);
if (fClass->IsLoaded() && ((TStreamerSTL*)element)->GetSTLtype() != ROOT::kSTLvector) {
if (!element->GetClassPointer()->IsLoaded()) {
Error("Build","The class \"%s\" is compiled and its base class \"%s\" is a collection and we do not have a dictionary for it, we will not be able to read or write this base class.",GetName(),bname);
delete element;
continue;
}
}
} else {
element = new TStreamerBase(bname, btitle, offset);
TClass* clm = element->GetClassPointer();
if (!clm) {
clm = new TClass(bname,1,TClass::kForwardDeclared, true );
Warning("Build", "%s: base class %s has no streamer or dictionary it will not be saved", GetName(), clm->GetName());
element->Init(0);
} else {
if ((clm == TObject::Class()) && fClass->CanIgnoreTObjectStreamer()) {
SetBit(kIgnoreTObjectStreamer);
element->SetType(-1);
}
if (!clm->IsLoaded() && !(isCollection || isString)) {
Warning("Build", "%s: base class %s has no streamer or dictionary it will not be saved", GetName(), clm->GetName());
}
}
}
if (element) {
fElements->Add(element);
}
}
Int_t dsize;
TDataMember* dm = 0;
TIter nextd(fClass->GetListOfDataMembers());
while ((dm = (TDataMember*) nextd())) {
if (fClass->GetClassVersion() == 0) {
continue;
}
if (!dm->IsPersistent()) {
continue;
}
TMemberStreamer* streamer = 0;
Int_t offset = GetDataMemberOffset(dm, streamer);
if (offset == kMissing) {
continue;
}
TStreamerElement* element = 0;
dsize = 0;
const char* dmName = dm->GetName();
const char* dmTitle = dm->GetTitle();
const char* dmType = dm->GetTypeName();
const char* dmFull = dm->GetTrueTypeName();
Bool_t dmIsPtr = dm->IsaPointer();
TDataMember* dmCounter = 0;
if (dmIsPtr) {
const char* lbracket = TVirtualStreamerInfo::GetElementCounterStart(dmTitle);
const char* rbracket = ::strchr(dmTitle, ']');
if (lbracket && rbracket) {
const char* counterName = dm->GetArrayIndex();
TRealData* rdCounter = (TRealData*) fClass->GetListOfRealData()->FindObject(counterName);
if (!rdCounter || rdCounter->TestBit(TRealData::kTransient)) {
Error("Build", "%s, discarding: %s %s, illegal %s\n", GetName(), dmFull, dmName, dmTitle);
continue;
}
dmCounter = rdCounter->GetDataMember();
TDataType* dtCounter = dmCounter->GetDataType();
Bool_t isInteger = dtCounter && ((dtCounter->GetType() == 3) || (dtCounter->GetType() == 13));
if (!dtCounter || !isInteger) {
Error("Build", "%s, discarding: %s %s, illegal [%s] (must be Int_t)\n", GetName(), dmFull, dmName, counterName);
continue;
}
TStreamerBasicType* bt = TStreamerInfo::GetElementCounter(counterName, dmCounter->GetClass());
if (!bt) {
if (dmCounter->GetClass()->Property() & kIsAbstract) {
continue;
}
Error("Build", "%s, discarding: %s %s, illegal [%s] must be placed before \n", GetName(), dmFull, dmName, counterName);
continue;
}
}
}
TDataType* dt = dm->GetDataType();
if (dt) {
Int_t dtype = dt->GetType();
dsize = dt->Size();
if (!dmCounter && (strstr(dmFull, "char*") || strstr(dmFull, "Char_t*"))) {
dtype = kCharStar;
dsize = sizeof(char*);
}
if (dtype == kOther_t || dtype == kNoType_t) {
Error("Build", "%s, unknown type: %s %s", GetName(), dmFull, dmName);
continue;
} else if (dmIsPtr && (dtype != kCharStar)) {
if (dmCounter) {
element = new TStreamerBasicPointer(dmName, dmTitle, offset, dtype, dm->GetArrayIndex(), dmCounter->GetClass()->GetName(), dmCounter->GetClass()->GetClassVersion(), dmFull);
} else {
if ((fName == "TString") || (fName == "TClass")) {
continue;
}
Error("Build", "%s, discarding: %s %s, no [dimension]\n", GetName(), dmFull, dmName);
continue;
}
} else {
if ((fClass == TObject::Class()) && !strcmp(dmName, "fBits")) {
dtype = kBits;
}
element = new TStreamerBasicType(dmName, dmTitle, offset, dtype, dmFull);
}
} else {
static const char* full_string_name = "basic_string<char,char_traits<char>,allocator<char> >";
if (!strcmp(dmType, "string") || !strcmp(dmType, "std::string") || !strcmp(dmType, full_string_name)) {
element = new TStreamerSTLstring(dmName, dmTitle, offset, dmFull, dmIsPtr);
} else if (dm->IsSTLContainer()) {
TVirtualCollectionProxy *proxy = TClass::GetClass(dm->GetTypeName() )->GetCollectionProxy();
if (proxy) element = new TStreamerSTL(dmName, dmTitle, offset, dmFull, *proxy, dmIsPtr);
else element = new TStreamerSTL(dmName, dmTitle, offset, dmFull, dm->GetTrueTypeName(), dmIsPtr);
if (((TStreamerSTL*)element)->GetSTLtype() != ROOT::kSTLvector) {
if (fClass->IsLoaded()) {
if (!element->GetClassPointer()->IsLoaded()) {
Error("Build","The class \"%s\" is compiled and for its the data member \"%s\", we do not have a dictionary for the collection \"%s\", we will not be able to read or write this data member.",GetName(),dmName,element->GetClassPointer()->GetName());
delete element;
continue;
}
} else if (fClass->GetState() == TClass::kInterpreted) {
if (element->GetClassPointer()->GetCollectionProxy()->GetProperties() & TVirtualCollectionProxy::kIsEmulated) {
Error("Build","The class \"%s\" is interpreted and for its the data member \"%s\", we do not have a dictionary for the collection \"%s\", we will not be able to read or write this data member.",GetName(),dmName,element->GetClassPointer()->GetName());
delete element;
continue;
}
}
}
} else {
TClass* clm = TClass::GetClass(dmType);
if (!clm) {
Error("Build", "%s, unknown type: %s %s\n", GetName(), dmFull, dmName);
continue;
}
if (dmIsPtr) {
if (dmCounter) {
element = new TStreamerLoop(dmName, dmTitle, offset, dm->GetArrayIndex(), dmCounter->GetClass()->GetName(), dmCounter->GetClass()->GetClassVersion(), dmFull);
} else {
if (clm->IsTObject()) {
element = new TStreamerObjectPointer(dmName, dmTitle, offset, dmFull);
} else {
element = new TStreamerObjectAnyPointer(dmName, dmTitle, offset, dmFull);
if (!streamer && !clm->GetStreamer() && !clm->IsLoaded()) {
Error("Build", "%s: %s has no streamer or dictionary, data member %s will not be saved", GetName(), dmFull, dmName);
}
}
}
} else if (clm->IsTObject()) {
element = new TStreamerObject(dmName, dmTitle, offset, dmFull);
} else if ((clm == TString::Class()) && !dmIsPtr) {
element = new TStreamerString(dmName, dmTitle, offset);
} else {
element = new TStreamerObjectAny(dmName, dmTitle, offset, dmFull);
if (!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 (!element) {
continue;
}
Int_t ndim = dm->GetArrayDim();
if (!dsize) {
dsize = dm->GetUnitSize();
}
for (Int_t i = 0; i < ndim; ++i) {
element->SetMaxIndex(i, dm->GetMaxIndex(i));
}
element->SetArrayDim(ndim);
Int_t narr = element->GetArrayLength();
if (!narr) {
narr = 1;
}
element->SetSize(dsize*narr);
element->SetStreamer(streamer);
if (!streamer) {
Int_t k = element->GetType();
if (k == kStreamer) {
element->SetType(-1);
}
}
if ( !wasCompiled && (rules && rules->HasRuleWithSource( element->GetName(), kTRUE )) ) {
needAllocClass = kTRUE;
TStreamerElement *cached = element;
if (element->GetNewType()>0
&& rules && !rules->HasRuleWithTarget( element->GetName(), kTRUE ) )
{
TStreamerElement *copy = (TStreamerElement*)element->Clone();
fElements->Add(copy);
copy->SetBit(TStreamerElement::kRepeat);
cached = copy;
} else {
TStreamerElement *writecopy = (TStreamerElement*)element->Clone();
fElements->Add(element);
writecopy->SetBit(TStreamerElement::kWrite);
writecopy->SetNewType( writecopy->GetType() );
element = writecopy;
}
cached->SetBit(TStreamerElement::kCache);
cached->SetNewType( cached->GetType() );
}
fElements->Add(element);
}
InsertArtificialElements(rules);
if (needAllocClass) {
TStreamerInfo *infoalloc = (TStreamerInfo *)Clone(TString::Format("%s@@%d",GetName(),GetClassVersion()));
if (!infoalloc) {
Error("Build","Could you create a TStreamerInfo for %s\n",TString::Format("%s@@%d",GetName(),GetClassVersion()).Data());
} else {
infoalloc->SetBit(kBuildOldUsed,false);
infoalloc->BuildCheck();
infoalloc->BuildOld();
TClass *allocClass = infoalloc->GetClass();
{
TIter next(fElements);
TStreamerElement* element;
while ((element = (TStreamerElement*) next())) {
if (element->TestBit(TStreamerElement::kRepeat) && element->IsaPointer()) {
TStreamerElement *other = (TStreamerElement*) infoalloc->GetElements()->FindObject(element->GetName());
if (other) {
other->SetBit(TStreamerElement::kDoNotDelete);
}
}
}
infoalloc->GetElements()->Compress();
}
{
TIter next(fElements);
TStreamerElement* element;
while ((element = (TStreamerElement*) next())) {
if (element->TestBit(TStreamerElement::kCache)) {
element->SetOffset(infoalloc->GetOffset(element->GetName()));
}
}
}
TStreamerElement *el = new TStreamerArtificial("@@alloc","", 0, TStreamerInfo::kCacheNew, allocClass->GetName());
R__TObjArray_InsertAt( fElements, el, 0 );
el = new TStreamerArtificial("@@dealloc","", 0, TStreamerInfo::kCacheDelete, allocClass->GetName());
fElements->Add( el );
}
}
Compile();
fIsBuilt = kTRUE;
}
void TStreamerInfo::BuildCheck(TFile *file )
{
R__LOCKGUARD(gInterpreterMutex);
fClass = TClass::GetClass(GetName());
if (!fClass) {
fClass = new TClass(GetName(), (Version_t)fClassVersion);
fClass->SetBit(TClass::kIsEmulation);
if (GetElements()->GetEntries() == 1) {
TObject *element = GetElements()->UncheckedAt(0);
Bool_t isstl = element && strcmp("This",element->GetName())==0;
if (isstl) {
if (element->GetTitle()[0] == '<') {
TString content = element->GetTitle();
Int_t level = 1;
for(Int_t c = 1; c < content.Length(); ++c) {
if (content[c] == '<') ++level;
else if (content[c] == '>') --level;
if (level == 0) {
content.Remove(c+1);
break;
}
}
content.Prepend("vector");
TClass *clequiv = TClass::GetClass(content);
TVirtualCollectionProxy *proxy = clequiv->GetCollectionProxy();
if (gDebug > 1)
Info("BuildCheck",
"Update the collection proxy of the class \"%s\" \n"
"\tto be similar to \"%s\".",
GetName(),content.Data());
fClass->CopyCollectionProxy( *proxy );
} else {
Warning("BuildCheck", "\n\
The class %s had a collection proxy when written but it is not an STL\n \
collection and we did not record the type of the content of the collection.\n \
We will claim the content is a bool (i.e. no data will be read).",
GetName());
}
}
}
} else {
if (fClass->GetCollectionType() > ROOT::kNotSTL) {
SetBit(kCanDelete);
return;
}
const TObjArray *array = fClass->GetStreamerInfos();
TStreamerInfo* info = 0;
if (fClass->TestBit(TClass::kIsEmulation) && array->GetEntries()==0) {
::Warning("TClass::TClass", "no dictionary for class %s is available", GetName());
}
if (GetElements()->GetEntries() == 1) {
TObject *element = GetElements()->UncheckedAt(0);
Bool_t isstl = element && strcmp("This",element->GetName())==0;
if (isstl && !fClass->GetCollectionProxy()) {
if (element->GetTitle()[0] == '<') {
TString content = element->GetTitle();
Int_t level = 1;
for(Int_t c = 1; c < content.Length(); ++c) {
if (content[c] == '<') ++level;
else if (content[c] == '>') --level;
if (level == 0) {
content.Remove(c+1);
break;
}
}
content.Prepend("vector");
TClass *clequiv = TClass::GetClass(content);
TVirtualCollectionProxy *proxy = clequiv->GetCollectionProxy();
if (gDebug > 1)
Info("BuildCheck",
"Update the collection proxy of the class \"%s\" \n"
"\tto be similar to \"%s\".",
GetName(),content.Data());
fClass->CopyCollectionProxy( *proxy );
} else {
Warning("BuildCheck", "\n\
The class %s had a collection proxy when written but it is not an STL\n \
collection and we did not record the type of the content of the collection.\n \
We will claim the content is a bool (i.e. no data will be read).",
GetName());
}
SetBit(kCanDelete);
return;
}
}
Bool_t searchOnChecksum = kFALSE;
if (fClass->IsLoaded() && fClass->GetClassVersion() >= 2) {
if (fOnFileClassVersion >= 2) {
searchOnChecksum = kFALSE;
} else {
searchOnChecksum = kTRUE;
}
} else if (fClass->IsLoaded() && !fClass->IsForeign()) {
searchOnChecksum = kFALSE;
} else if (fClass->IsLoaded() ) {
searchOnChecksum = kTRUE;
}
else {
if (fOnFileClassVersion >= 2) {
searchOnChecksum = kFALSE;
} else {
searchOnChecksum = kTRUE;
TStreamerInfo* v1 = (TStreamerInfo*) array->At(1);
if (v1) {
if (fCheckSum != v1->GetCheckSum()) {
fClassVersion = array->GetLast() + 1;
}
}
}
}
if (!searchOnChecksum) {
if (fClassVersion < array->GetEntriesFast()) {
info = (TStreamerInfo*) array->At(fClassVersion);
}
} else {
Int_t ninfos = array->GetEntriesFast() - 1;
for (Int_t i = -1; i < ninfos; ++i) {
info = (TStreamerInfo*) array->UncheckedAt(i);
if (!info) {
continue;
}
if (fCheckSum == info->GetCheckSum() && (info->GetOnFileClassVersion()==1 || info->GetOnFileClassVersion()==0)) {
fClassVersion = i;
break;
}
info = 0;
}
if (info==0) {
ninfos = array->GetEntriesFast() - 1;
Int_t slot = 1;
while ((slot < ninfos) && (array->UncheckedAt(slot) != 0)) {
++slot;
}
fClassVersion = slot;
}
}
if (info) {
Bool_t match = kTRUE;
Bool_t done = kFALSE;
Bool_t oldIsNonVersioned = kFALSE;
if (fClassVersion!=0 && !fClass->TestBit(TClass::kWarned) && (fClassVersion == info->GetClassVersion()) && (fCheckSum != info->GetCheckSum())) {
match = kFALSE;
oldIsNonVersioned = info->fOnFileClassVersion==1 && info->fClassVersion != 1;
if (fClass->IsLoaded() && (fClassVersion == fClass->GetClassVersion()) && fClass->HasDataMemberInfo()) {
if ( (fCheckSum == fClass->GetCheckSum() || fClass->MatchLegacyCheckSum(fCheckSum) )
&&(info->GetCheckSum() == fClass->GetCheckSum() || fClass->MatchLegacyCheckSum(info->GetCheckSum()))
)
{
match = kTRUE;
}
if (fOldVersion <= 2) {
match = kTRUE;
}
if (!match && CompareContent(0,info,kFALSE,kFALSE,file)) {
match = kTRUE;
}
#ifdef TEST_FOR_BACKWARD_COMPATIBILITY_ABSTRACT_CLASSES
if (!match && file->GetVersion() < 51800 && fClass && (fClass->Property() & kIsAbstract)
&& fClass->GetListOfDataMembers()->GetEntries() != 0)
{
}
#endif
} else {
match = kFALSE;
oldIsNonVersioned = info->fOnFileClassVersion==1 && info->fClassVersion != 1;
if (fCheckSum == info->GetCheckSum(TClass::kCurrentCheckSum)
|| info->MatchLegacyCheckSum(fCheckSum)
|| GetCheckSum(TClass::kCurrentCheckSum) == info->fCheckSum
|| MatchLegacyCheckSum(info->GetCheckSum())
|| GetCheckSum(TClass::kCurrentCheckSum) == info->GetCheckSum(TClass::kCurrentCheckSum))
{
match = kTRUE;
}
if (fOldVersion <= 2) {
match = kTRUE;
}
if (!match && CompareContent(0,info,kFALSE,kFALSE,file)) {
match = kTRUE;
}
}
}
if (info->IsBuilt()) {
SetBit(kCanDelete);
fNumber = info->GetNumber();
Int_t nel = fElements->GetEntriesFast();
TObjArray* elems = info->GetElements();
TStreamerElement* e1 = 0;
TStreamerElement* e2 = 0;
for (Int_t i = 0; i < nel; ++i) {
e1 = (TStreamerElement*) fElements->UncheckedAt(i);
e2 = (TStreamerElement*) elems->At(i);
if (!e1 || !e2) {
continue;
}
if (strlen(e1->GetTitle()) != strlen(e2->GetTitle())) {
e2->SetTitle(e1->GetTitle());
}
}
done = kTRUE;
} else {
fClass->RemoveStreamerInfo(fClassVersion);
info = 0;
}
TString origin;
if (!match && !fClass->TestBit(TClass::kWarned)) {
if (oldIsNonVersioned) {
if (file) {
Warning("BuildCheck", "\n\
The class %s transitioned from not having a specified class version\n\
to having a specified class version (the current class version is %d).\n\
However too many different non-versioned layouts of the class have been\n\
loaded so far. This prevent the proper reading of objects written with\n\
the class layout version %d, in particular from the file:\n\
%s.\n\
To work around this issue, load fewer 'old' files in the same ROOT session.",
GetName(),fClass->GetClassVersion(),fClassVersion,file->GetName());
} else {
Warning("BuildCheck", "\n\
The class %s transitioned from not having a specified class version\n\
to having a specified class version (the current class version is %d).\n\
However too many different non-versioned layouts of the class have been\n\
loaded so far. This prevent the proper reading of objects written with\n\
the class layout version %d.\n\
To work around this issue, load fewer 'old' files in the same ROOT session.",
GetName(),fClass->GetClassVersion(),fClassVersion);
}
} else {
if (file) {
if (done) {
Warning("BuildCheck", "\n\
The StreamerInfo for version %d of class %s read from the file %s\n\
has a different checksum than the previously loaded StreamerInfo.\n\
Reading objects of type %s from the file %s \n\
(and potentially other files) might not work correctly.\n\
Most likely the version number of the class was not properly\n\
updated [See ClassDef(%s,%d)].",
fClassVersion, GetName(), file->GetName(), GetName(), file->GetName(), GetName(), fClassVersion);
} else {
Warning("BuildCheck", "\n\
The StreamerInfo from %s does not match existing one (%s:%d)\n\
The existing one has not been used yet and will be discarded.\n\
Reading the file %s will work properly, however writing object of\n\
type %s will not work properly. Most likely the version number\n\
of the class was not properly updated [See ClassDef(%s,%d)].",
file->GetName(), GetName(), fClassVersion,file->GetName(),GetName(), GetName(), fClassVersion);
}
} else {
if (done) {
Warning("BuildCheck", "\n\
The StreamerInfo for version %d of class %s\n\
has a different checksum than the previously loaded StreamerInfo.\n\
Reading objects of type %s\n\
(and potentially other files) might not work correctly.\n\
Most likely the version number of the class was not properly\n\
updated [See ClassDef(%s,%d)].",
fClassVersion, GetName(), GetName(), GetName(), fClassVersion);
} else {
Warning("BuildCheck", "\n\
The StreamerInfo from %s does not match existing one (%s:%d)\n\
The existing one has not been used yet and will be discarded.\n\
Reading should work properly, however writing object of\n\
type %s will not work properly. Most likely the version number\n\
of the class was not properly updated [See ClassDef(%s,%d)].",
file->GetName(), GetName(), fClassVersion, GetName(), GetName(), fClassVersion);
}
}
}
CompareContent(0,info,kTRUE,kTRUE,file);
fClass->SetBit(TClass::kWarned);
}
if (done) {
return;
}
}
if (fClass->IsLoaded()
&& fClass->HasDataMemberInfo()
&& (fClassVersion != 0)
&& (fClassVersion == fClass->GetClassVersion())
&& (fCheckSum != fClass->GetCheckSum())) {
if (!fClass->MatchLegacyCheckSum(fCheckSum)) {
Bool_t warn = !fClass->TestBit(TClass::kWarned);
if (warn) {
warn = !CompareContent(fClass,0,kFALSE,kFALSE,file);
}
#ifdef TEST_FOR_BACKWARD_COMPATIBILITY_ABSTRACT_CLASSES
if (warn && file->GetVersion() < 51800 && fClass && (fClass->Property() & kIsAbstract)
&& fClass->GetListOfDataMembers()->GetEntries() != 0)
{
}
#endif // TEST_FOR_BACKWARD_COMPATIBILITY
if (warn && (fOldVersion <= 2)) {
TIter nextBC(fClass->GetListOfBases());
TBaseClass* bc = 0;
while ((bc = (TBaseClass*) nextBC())) {
if (bc->GetClassPointer()->GetCollectionType()) {
warn = kFALSE;
}
}
}
if (warn) {
if (file) {
Warning("BuildCheck", "\n\
The StreamerInfo of class %s read from file %s\n\
has the same version (=%d) as the active class but a different checksum.\n\
You should update the version to ClassDef(%s,%d).\n\
Do not try to write objects with the current class definition,\n\
the files will not be readable.\n", GetName(), file->GetName(), fClassVersion, GetName(), fClassVersion + 1);
} else {
Warning("BuildCheck", "\n\
The StreamerInfo of class %s \n\
has the same version (=%d) as the active class but a different checksum.\n\
You should update the version to ClassDef(%s,%d).\n\
Do not try to write objects with the current class definition,\n\
the files will not be readable.\n", GetName(), fClassVersion, GetName(), fClassVersion + 1);
}
CompareContent(fClass,0,kTRUE,kTRUE,file);
fClass->SetBit(TClass::kWarned);
}
} else {
if (!fClass->IsVersioned()) {
Fatal("BuildCheck", "\n\
The StreamerInfo of unversioned class %s \n\
has the same version (=%d) as the active class but an old checksum.\n\
This should not happen. An assert will follow.\n", GetName(), fClassVersion);
}
}
}
if (!fClass->IsLoaded() && this->fOnFileClassVersion>1)
{
ROOT::ResetClassVersion(fClass,(const char*)-1, this->fClassVersion);
}
}
if (TestBit(kIgnoreTObjectStreamer)) {
fClass->IgnoreTObjectStreamer();
}
if ((fClassVersion < -1) || (fClassVersion > 65000)) {
printf("ERROR reading TStreamerInfo: %s fClassVersion=%d\n", GetName(), fClassVersion);
SetBit(kCanDelete);
fNumber = -1;
return;
}
if (!fClass->TestBit(TClass::kWarned)
&& fClass->GetState() >= TClass::kInterpreted
&& GetCheckSum() != fClass->GetCheckSum()
&& fClassVersion == fClass->GetClassVersion()) {
SetBit(kCanDelete);
return;
}
fClass->RegisterStreamerInfo(this);
++fgCount;
fNumber = fgCount;
fIsBuilt = kTRUE;
TObjArray* infos = (TObjArray*) gROOT->GetListOfStreamerInfo();
infos->AddAtAndExpand(this, fNumber);
}
void TStreamerInfo::BuildEmulated(TFile *file)
{
R__LOCKGUARD(gInterpreterMutex);
TString duName;
R__ASSERT(file);
Int_t fv = file->GetVersion()%100000;
R__ASSERT(fv < 30000);
fClassVersion = -1;
fCheckSum = 2001;
TObjArray *elements = GetElements();
Int_t ndata = elements ? elements->GetEntries() : 0;
for (Int_t i=0;i < ndata;i++) {
TStreamerElement *element = (TStreamerElement*)elements->UncheckedAt(i);
if (!element) break;
int ty = element->GetType();
if (ty < kChar || ty >kULong+kOffsetL) continue;
if (ty == kLong) element->SetType(kInt);
if (ty == kULong) element->SetType(kUInt);
if (ty == kLong + kOffsetL) element->SetType(kInt + kOffsetL);
if (ty == kULong + kOffsetL) element->SetType(kUInt + kOffsetL);
if (ty <= kULong) continue;
duName = element->GetName();
duName.Append("QWERTY");
TStreamerBasicType *bt = new TStreamerBasicType(duName, "", 0, kInt,"Int_t");
{for (int j=ndata-1;j>=i;j--) {elements->AddAtAndExpand(elements->At(j),j+1);}}
elements->AddAt(bt,i);
ndata++;
i++;
}
BuildOld();
}
Bool_t TStreamerInfo::BuildFor( const TClass *in_memory_cl )
{
R__LOCKGUARD(gInterpreterMutex);
if( !in_memory_cl || !in_memory_cl->GetSchemaRules() ) {
return kFALSE;
}
const TObjArray* rules;
rules = in_memory_cl->GetSchemaRules()->FindRules( GetName(), fOnFileClassVersion, fCheckSum );
if( !rules && !in_memory_cl->GetCollectionType() ) {
Warning( "BuildFor", "The build of %s streamer info for %s has been requested, but no matching conversion rules were specified", GetName(), in_memory_cl->GetName() );
return kFALSE;
}
fClass = const_cast<TClass*>(in_memory_cl);
return kTRUE;
}
namespace {
Bool_t ClassWasMovedToNamespace(TClass *oldClass, TClass *newClass)
{
if (oldClass == 0 || newClass == 0) return kFALSE;
UInt_t newlen = strlen(newClass->GetName());
UInt_t oldlen = strlen(oldClass->GetName());
const char *oldname = oldClass->GetName();
for (UInt_t i = oldlen, done = false, nest = 0; (i>0) && !done ; --i) {
switch (oldClass->GetName()[i-1]) {
case '>' : ++nest; break;
case '<' : if (nest==0) return kFALSE;
--nest; break;
case ':' : if (nest == 0) oldname= &(oldClass->GetName()[i]); done = kTRUE; break;
}
}
oldlen = strlen(oldname);
if (!(strlen(newClass->GetName()) > strlen(oldClass->GetName()))) {
return kFALSE;
}
const char* newEnd = & (newClass->GetName()[newlen-oldlen]);
if (0 != strcmp(newEnd, oldname)) {
return kFALSE;
}
Int_t oldv = oldClass->GetStreamerInfo()->GetClassVersion();
if (newClass->GetStreamerInfos() && oldv < newClass->GetStreamerInfos()->GetSize() && newClass->GetStreamerInfos()->At(oldv) && strcmp(newClass->GetStreamerInfos()->At(oldv)->GetName(), oldClass->GetName()) != 0) {
return kFALSE;
}
return kTRUE;
}
Int_t ImportStreamerInfo(TClass *oldClass, TClass *newClass) {
TIter next(oldClass->GetStreamerInfos());
TStreamerInfo *info;
while ((info = (TStreamerInfo*)next())) {
info = (TStreamerInfo*)info->Clone();
if (!info) {
Error("ImportStreamerInfo","Unable to clone the StreamerInfo for %s.",(*next)->GetName());
} else {
info->SetClass(newClass);
Int_t oldv = info->GetClassVersion();
if (oldv > newClass->GetStreamerInfos()->GetSize() || newClass->GetStreamerInfos()->At(oldv) == 0) {
newClass->RegisterStreamerInfo(info);
} else {
if (strcmp(newClass->GetStreamerInfos()->At(oldv)->GetName(),
oldClass->GetName()) != 0) {
return oldv;
}
}
}
}
return 0;
}
Bool_t ContainerMatchTClonesArray(TClass *newClass)
{
return newClass->GetCollectionProxy()
&& newClass->GetCollectionProxy()->GetValueClass()
&& !newClass->GetCollectionProxy()->HasPointers();
}
Bool_t CollectionMatch(const TClass *oldClass, const TClass* newClass)
{
TVirtualCollectionProxy *oldProxy = oldClass->GetCollectionProxy();
TVirtualCollectionProxy *newProxy = newClass->GetCollectionProxy();
TClass *oldContent = oldProxy->GetValueClass();
TClass *newContent = newProxy->GetValueClass();
Bool_t contentMatch = kFALSE;
if (oldContent) {
if (oldContent == newContent) {
contentMatch = kTRUE;
} else if (newContent) {
TString oldFlatContent( TMakeProject::UpdateAssociativeToVector(oldContent->GetName()) );
TString newFlatContent( TMakeProject::UpdateAssociativeToVector(newContent->GetName()) );
if (oldFlatContent == newFlatContent) {
contentMatch = kTRUE;
}
} else {
contentMatch = kFALSE;
}
} else {
contentMatch = (newContent==0);
}
if (contentMatch) {
if ((oldContent==0 && oldProxy->GetType() == newProxy->GetType())
||(oldContent && oldProxy->HasPointers() == newProxy->HasPointers())) {
return kTRUE;
}
}
return kFALSE;
}
Bool_t CollectionMatchFloat16(const TClass *oldClass, const TClass* newClass)
{
TVirtualCollectionProxy *oldProxy = oldClass->GetCollectionProxy();
TVirtualCollectionProxy *newProxy = newClass->GetCollectionProxy();
if (oldProxy->GetValueClass() == 0 && newProxy->GetValueClass() == 0
&& (oldProxy->GetType() == kFloat_t || oldProxy->GetType() == kFloat16_t)
&& (newProxy->GetType() == kFloat_t || newProxy->GetType() == kFloat16_t )) {
return (oldClass->GetCollectionType() == newClass->GetCollectionType());
}
return kFALSE;
}
Bool_t CollectionMatchDouble32(const TClass *oldClass, const TClass* newClass)
{
TVirtualCollectionProxy *oldProxy = oldClass->GetCollectionProxy();
TVirtualCollectionProxy *newProxy = newClass->GetCollectionProxy();
if (oldProxy->GetValueClass() == 0 && newProxy->GetValueClass() == 0
&& (oldProxy->GetType() == kDouble_t || oldProxy->GetType() == kDouble32_t)
&& (newProxy->GetType() == kDouble_t || newProxy->GetType() == kDouble32_t )) {
return (oldClass->GetCollectionType() == newClass->GetCollectionType());
}
return kFALSE;
}
Bool_t CollectionMatchLong64(const TClass *oldClass, const TClass* newClass)
{
TVirtualCollectionProxy *oldProxy = oldClass->GetCollectionProxy();
TVirtualCollectionProxy *newProxy = newClass->GetCollectionProxy();
if (oldProxy->GetValueClass() == 0 && newProxy->GetValueClass() == 0
&& (oldProxy->GetType() == kLong_t || oldProxy->GetType() == kLong64_t)
&& (newProxy->GetType() == kLong_t || newProxy->GetType() == kLong64_t )) {
return (oldClass->GetCollectionType() == newClass->GetCollectionType());
}
return kFALSE;
}
Bool_t CollectionMatchULong64(const TClass *oldClass, const TClass* newClass)
{
TVirtualCollectionProxy *oldProxy = oldClass->GetCollectionProxy();
TVirtualCollectionProxy *newProxy = newClass->GetCollectionProxy();
if (oldProxy->GetValueClass() == 0 && newProxy->GetValueClass() == 0
&& (oldProxy->GetType() == kULong_t || oldProxy->GetType() == kULong64_t)
&& (newProxy->GetType() == kULong_t || newProxy->GetType() == kULong64_t )) {
return (oldClass->GetCollectionType() == newClass->GetCollectionType());
}
return kFALSE;
}
TClass *FindAlternate(TClass *context, const std::string &i_name, std::string& newName)
{
std::string name(i_name);
newName.clear();
if (name.compare(0,6,"const ")==0) {
newName = "const ";
name.erase(0,6);
}
std::string suffix;
UInt_t nstars = 0;
while(name[name.length()-nstars-1]=='*') {
++nstars;
suffix.append("*");
}
if (nstars) {
name.erase(name.length()-nstars,nstars);
}
std::string alternate(context->GetName());
alternate.append("::");
alternate.append(name);
TClass *altcl = TClass::GetClass(alternate.c_str(), false,true);
if (altcl) {
newName.append(altcl->GetName());
newName.append(suffix);
return altcl;
}
size_t ctxt_cursor = strlen(context->GetName());
for (size_t level = 0; ctxt_cursor != 0; --ctxt_cursor) {
switch (context->GetName()[ctxt_cursor]) {
case '<': --level; break;
case '>': ++level; break;
case ':': if (level == 0) {
alternate.clear();
alternate.append(context->GetName(),ctxt_cursor+1);
alternate.append(name);
altcl = TClass::GetClass(alternate.c_str(), false,true);
if (altcl) {
newName.append(altcl->GetName());
newName.append(suffix);
return altcl;
}
}
}
}
newName.clear();
return 0;
}
bool HasScope(const std::string &name)
{
for(size_t i = 0, level = 0; i<name.length(); ++i) {
switch (name[i]) {
case '<': ++level; break;
case '>': --level; break;
case ':': if (level == 0) {
return true;
}
}
}
return false;
}
TClass *FixCollectionV5(TClass *context, TClass *oldClass, TClass *newClass)
{
assert(oldClass->GetCollectionProxy() && newClass->GetCollectionProxy());
TVirtualCollectionProxy *old = oldClass->GetCollectionProxy();
TVirtualCollectionProxy *current = newClass->GetCollectionProxy();
Int_t stlkind = old->GetCollectionType();
if (stlkind == ROOT::kSTLmap || stlkind == ROOT::kSTLmultimap) {
TVirtualStreamerInfo *info = current->GetValueClass()->GetStreamerInfo();
if (info->GetElements()->GetEntries() != 2) {
return oldClass;
}
TStreamerElement *f = (TStreamerElement*) info->GetElements()->At(0);
TStreamerElement *s = (TStreamerElement*) info->GetElements()->At(1);
info = old->GetValueClass()->GetStreamerInfo();
assert(info->GetElements()->GetEntries() == 2);
TStreamerElement *of = (TStreamerElement*) info->GetElements()->At(0);
TStreamerElement *os = (TStreamerElement*) info->GetElements()->At(1);
TClass *firstNewCl = f ? f->GetClass() : 0;
TClass *secondNewCl = s ? s->GetClass() : 0;
TClass *firstOldCl = of ? of->GetClass() : 0;
TClass *secondOldCl = os ? os->GetClass() : 0;
if ((firstNewCl && !firstOldCl) || (secondNewCl && !secondOldCl))
{
std::vector<std::string> inside;
int nestedLoc;
TClassEdit::GetSplit( oldClass->GetName(), inside, nestedLoc, TClassEdit::kLong64 );
TClass *firstAltCl = firstOldCl;
TClass *secondAltCl = secondOldCl;
std::string firstNewName;
std::string secondNewName;
if (firstNewCl && !HasScope(inside[1])) {
firstAltCl = FindAlternate(context, inside[1], firstNewName);
}
if (secondNewCl && !HasScope(inside[2])) {
secondAltCl = FindAlternate(context, inside[2], secondNewName);
}
if ((firstNewCl && firstAltCl != firstOldCl) ||
(secondNewCl && secondAltCl != secondOldCl) ) {
std::string alternate = inside[0];
alternate.append("<");
alternate.append(firstAltCl ? firstNewName : inside[1]);
alternate.append(",");
alternate.append(secondAltCl? secondNewName : inside[2]);
if (alternate[alternate.length()-1]=='>') {
alternate.append(" ");
}
alternate.append(">");
return TClass::GetClass(alternate.c_str(),true,true);
}
}
} else if (current->GetValueClass() && !old->GetValueClass()
&& old->GetType() == kInt_t) {
std::vector<std::string> inside;
int nestedLoc;
TClassEdit::GetSplit( oldClass->GetName(), inside, nestedLoc, TClassEdit::kLong64 );
if (HasScope(inside[1])) {
return oldClass;
}
std::string newName;
TClass *altcl = FindAlternate(context, inside[1], newName);
if (altcl) {
std::string alternate = inside[0];
alternate.append("<");
alternate.append(newName);
if (alternate[alternate.length()-1]=='>') {
alternate.append(" ");
}
alternate.append(">");
return TClass::GetClass(alternate.c_str(),true,true);
}
}
return 0;
}
struct TBuildOldGuard {
TBuildOldGuard(TStreamerInfo* info): fInfo(info) {
fInfo->SetBit(TStreamerInfo::kBuildRunning);
}
~TBuildOldGuard() {
fInfo->ResetBit(TStreamerInfo::kBuildRunning);
fInfo->SetBit(TStreamerInfo::kBuildOldUsed);
}
TStreamerInfo* fInfo;
};
}
void TStreamerInfo::BuildOld()
{
R__LOCKGUARD(gInterpreterMutex);
if ( TestBit(kBuildOldUsed) ) return;
if (TestBit(TStreamerInfo::kBuildRunning)) return;
TBuildOldGuard buildOldGuard(this);
if (gDebug > 0) {
printf("\n====>Rebuilding TStreamerInfo for class: %s, version: %d\n", GetName(), fClassVersion);
}
Bool_t wasCompiled = IsCompiled();
if (fClass->GetClassVersion() == fClassVersion) {
if (!fClass->HasInterpreterInfo() || fClass->GetCollectionType() || TClassEdit::IsSTLBitset(GetName()))
{
} else {
fClass->BuildRealData();
}
}
else {
fClass->GetStreamerInfo();
}
TIter next(fElements);
TStreamerElement* element;
Int_t offset = 0;
TMemberStreamer* streamer = 0;
Int_t sp = sizeof(void*);
int nBaze = 0;
if ((fElements->GetEntries() == 1) && !strcmp(fElements->At(0)->GetName(), "This")) {
if (fClass->GetCollectionProxy()) {
element = (TStreamerElement*)next();
element->SetNewType( element->GetType() );
element->SetNewClass( fClass );
} else if (((TStreamerElement*)fElements->At(0))->GetType() == TStreamerInfo::kSTL &&
strcmp( ((TStreamerElement*)fElements->At(0))->GetTypeName(),GetName()) != 0) {
}
}
TClass *allocClass = 0;
TStreamerInfo *infoalloc = 0;
const ROOT::TSchemaMatch* rules = 0;
const ROOT::TSchemaRuleSet* ruleSet = fClass->GetSchemaRules();
rules = (ruleSet ? ruleSet->FindRules( GetName(), fOnFileClassVersion, fCheckSum ) : 0);
Bool_t shouldHaveInfoLoc = fClass->TestBit(TClass::kIsEmulation) && !TClassEdit::IsStdClass(fClass->GetName());
Int_t virtualInfoLocAlloc = 0;
fNVirtualInfoLoc = 0;
delete [] fVirtualInfoLoc;
fVirtualInfoLoc = 0;
while ((element = (TStreamerElement*) next())) {
if (element->IsA()==TStreamerArtificial::Class()
|| element->TestBit(TStreamerElement::kCache) )
{
continue;
};
element->SetNewType(element->GetType());
if (element->IsBase()) {
if (element->IsA() == TStreamerBase::Class()) {
TStreamerBase* base = (TStreamerBase*) element;
#if defined(PROPER_IMPLEMEMANTION_OF_BASE_CLASS_RENAMING)
TClass* baseclass = fClass->GetBaseClass( base->GetName() );
#else
TClass* baseclass = base->GetClassPointer();
#endif
if( !baseclass && !fClass->TestBit( TClass::kIsEmulation ) ) {
const ROOT::TSchemaRule* rule = (rules ? rules->GetRuleWithSource( base->GetName() ) : 0);
if( !rule ) {
Error("BuildOld", "Could not find base class: %s for %s and could not find any matching rename rule\n", base->GetName(), GetName());
continue;
}
const TObjArray* targets = rule->GetTarget();
if( !targets ) {
Error("BuildOld", "Could not find base class: %s for %s, renaming rule was found but is malformed\n", base->GetName(), GetName());
}
TString newBaseClass = ((TObjString*)targets->At(0))->GetString();
baseclass = TClass::GetClass( newBaseClass );
base->SetNewBaseClass( baseclass );
}
else if( !baseclass ) {
baseclass = base->GetClassPointer();
if (!baseclass) {
Warning("BuildOld", "Missing base class: %s skipped", base->GetName());
baseclass = new TClass(element->GetName(), 1, 0, 0, -1, -1);
element->Update(0, baseclass);
}
}
baseclass->BuildRealData();
Int_t baseOffset = fClass->GetBaseClassOffset(baseclass);
if (baseOffset < 0) {
TList* listOfBases = fClass->GetListOfBases();
if (listOfBases) {
TBaseClass* bc = 0;
TIter nextBC(fClass->GetListOfBases());
while ((bc = (TBaseClass*) nextBC())) {
TClass *in_memory_bcl = bc->GetClassPointer();
if (in_memory_bcl && in_memory_bcl->GetSchemaRules()) {
auto baserule = in_memory_bcl->GetSchemaRules()->FindRules( base->GetName(), base->GetBaseVersion(), base->GetBaseCheckSum() );
if (baserule) {
base->SetNewBaseClass(in_memory_bcl);
baseOffset = bc->GetDelta();
}
}
}
}
}
element->Init(this);
TStreamerInfo* infobase;
if (fClass->TestBit(TClass::kIsEmulation) && (baseclass->Property() & kIsAbstract)) {
Int_t version = base->GetBaseVersion();
if (version >= 0 || base->GetBaseCheckSum() == 0) {
infobase = (TStreamerInfo*)baseclass->GetStreamerInfoAbstractEmulated(version);
} else {
infobase = (TStreamerInfo*)baseclass->FindStreamerInfoAbstractEmulated(base->GetBaseCheckSum());
}
if (infobase) baseclass = infobase->GetClass();
}
else {
infobase = (TStreamerInfo*)base->GetBaseStreamerInfo();
}
if (infobase && infobase->fComp == 0) {
infobase->BuildOld();
}
if (infobase && shouldHaveInfoLoc && baseclass->TestBit(TClass::kIsEmulation) ) {
if ( (fNVirtualInfoLoc + infobase->fNVirtualInfoLoc) > virtualInfoLocAlloc ) {
ULong_t *store = fVirtualInfoLoc;
virtualInfoLocAlloc = 16 * ( (fNVirtualInfoLoc + infobase->fNVirtualInfoLoc) / 16 + 1);
fVirtualInfoLoc = new ULong_t[virtualInfoLocAlloc];
if (store) {
memcpy(fVirtualInfoLoc, store, sizeof(ULong_t)*fNVirtualInfoLoc);
delete [] store;
}
}
for (int nloc = 0; nloc < infobase->fNVirtualInfoLoc; ++nloc) {
fVirtualInfoLoc[ fNVirtualInfoLoc + nloc ] = baseOffset + infobase->fVirtualInfoLoc[nloc];
}
fNVirtualInfoLoc += infobase->fNVirtualInfoLoc;
}
{
if (baseOffset < 0) {
element->SetNewType(-1);
}
}
element->SetOffset(baseOffset);
offset += baseclass->Size();
continue;
} else {
nBaze++;
TList* listOfBases = fClass->GetListOfBases();
Int_t baseOffset = -1;
Int_t asize = 0;
if (listOfBases) {
TBaseClass* bc = 0;
TIter nextBC(fClass->GetListOfBases());
while ((bc = (TBaseClass*) nextBC())) {
if (strchr(bc->GetName(), '<') || !strcmp(bc->GetName(),"string")) {
TString bcName(TClassEdit::ShortType(bc->GetName(), TClassEdit::kDropStlDefault).c_str());
TString elName(TClassEdit::ShortType(element->GetTypeName(), TClassEdit::kDropStlDefault).c_str());
if (bcName == elName) {
break;
}
}
}
if (!bc) {
Error("BuildOld", "Could not find STL base class: %s for %s\n", element->GetName(), GetName());
continue;
} else if (bc->GetClassPointer()->GetCollectionProxy()
&& !bc->GetClassPointer()->IsLoaded()
&& bc->GetClassPointer()->GetCollectionProxy()->GetCollectionType() != ROOT::kSTLvector) {
Error("BuildOld","The class \"%s\" is compiled and its base class \"%s\" is a collection and we do not have a dictionary for it, we will not be able to read or write this base class.",GetName(),bc->GetName());
offset = kMissing;
element->SetOffset(kMissing);
element->SetNewType(-1);
continue;
}
baseOffset = bc->GetDelta();
asize = bc->GetClassPointer()->Size();
} else if (fClass->TestBit( TClass::kIsEmulation )) {
TStreamerInfo* newInfo = (TStreamerInfo*) fClass->GetStreamerInfos()->At(fClass->GetClassVersion());
if (newInfo == this) {
baseOffset = offset;
asize = element->GetSize();
} else if (newInfo) {
TIter newElems( newInfo->GetElements() );
TStreamerElement *newElement;
while( (newElement = (TStreamerElement*)newElems()) ) {
const char *newElName = newElement->GetName();
if (newElement->IsBase() && (strchr(newElName,'<') || !strcmp(newElName,"string")) ) {
TString bcName(TClassEdit::ShortType(newElName, TClassEdit::kDropStlDefault).c_str());
TString elName(TClassEdit::ShortType(element->GetTypeName(), TClassEdit::kDropStlDefault).c_str());
if (bcName == elName) {
break;
}
}
}
if (!newElement) {
Error("BuildOld", "Could not find STL base class: %s for %s\n", element->GetName(), GetName());
continue;
}
baseOffset = newElement->GetOffset();
asize = newElement->GetSize();
}
}
if (baseOffset == -1) {
TClass* cb = element->GetClassPointer();
if (!cb) {
element->SetNewType(-1);
continue;
}
asize = cb->Size();
baseOffset = fClass->GetBaseClassOffset(cb);
}
if (baseOffset < 0) {
element->SetNewType(-1);
continue;
}
element->SetOffset(baseOffset);
offset += asize;
element->Init(this);
continue;
}
}
if (shouldHaveInfoLoc && fNVirtualInfoLoc==0) {
fNVirtualInfoLoc = 1;
fVirtualInfoLoc = new ULong_t[1];
fVirtualInfoLoc[0] = offset;
offset += sizeof(TStreamerInfo*);
}
TDataMember* dm = 0;
if (fClass->GetState() <= TClass::kEmulated) {
streamer = 0;
element->Init(this);
} else {
dm = (TDataMember*) fClass->GetListOfDataMembers()->FindObject(element->GetName());
if (dm && dm->IsPersistent()) {
fClass->BuildRealData();
streamer = 0;
offset = GetDataMemberOffset(dm, streamer);
element->SetOffset(offset);
element->Init(this);
TString dmClassName = TClassEdit::ShortType(dm->GetTypeName(),TClassEdit::kDropStlDefault).c_str();
dmClassName = dmClassName.Strip(TString::kTrailing, '*');
if (dmClassName.Index("const ")==0) dmClassName.Remove(0,6);
TClass *elemDm = !dm->IsBasic() ? TClass::GetClass(dmClassName.Data()) : 0;
if (elemDm && elemDm->GetCollectionProxy()
&& !elemDm->IsLoaded()
&& elemDm->GetCollectionProxy()->GetCollectionType() != ROOT::kSTLvector) {
Error("BuildOld","The class \"%s\" is compiled and for its data member \"%s\", we do not have a dictionary for the collection \"%s\", we will not be able to read or write this data member.",GetName(),dm->GetName(),elemDm->GetName());
offset = kMissing;
element->SetOffset(kMissing);
element->SetNewType(-1);
}
element->SetStreamer(streamer);
int narr = element->GetArrayLength();
if (!narr) {
narr = 1;
}
int dsize = dm->GetUnitSize();
element->SetSize(dsize*narr);
} else {
TRealData* rd = fClass->GetRealData(element->GetName());
if (rd && rd->GetDataMember()) {
element->SetOffset(rd->GetThisOffset());
element->Init(this);
dm = rd->GetDataMember();
int narr = element->GetArrayLength();
if (!narr) {
narr = 1;
}
int dsize = dm->GetUnitSize();
element->SetSize(dsize*narr);
}
}
}
Int_t newType = -1;
TClassRef newClass;
if (dm && dm->IsPersistent()) {
if (dm->GetDataType()) {
Bool_t isPointer = dm->IsaPointer();
Bool_t isArray = element->GetArrayLength() >= 1;
Bool_t hasCount = element->HasCounter();
if ((fClass == TObject::Class()) && !strcmp(dm->GetName(), "fBits")) {
newType = kBits;
} else {
newType = (EReadWrite)dm->GetDataType()->GetType();
}
if ((newType == ::kChar_t) && isPointer && !isArray && !hasCount) {
newType = ::kCharStar;
} else if (isPointer) {
newType += kOffsetP;
} else if (isArray) {
newType += kOffsetL;
}
}
if (newType == -1) {
newClass = TClass::GetClass(dm->GetTypeName());
}
} else {
if (!fClass->IsLoaded()) {
TStreamerInfo* newInfo = (TStreamerInfo*) fClass->GetStreamerInfos()->At(fClass->GetClassVersion());
if (newInfo && (newInfo != this)) {
TStreamerElement* newElems = (TStreamerElement*) newInfo->GetElements()->FindObject(element->GetName());
newClass = newElems ? newElems->GetClassPointer() : 0;
if (newClass == 0) {
newType = newElems ? newElems->GetType() : -1;
if (!(newType < kObject)) {
newType = -1;
}
}
} else {
newClass = element->GetClassPointer();
if (newClass.GetClass() == 0) {
newType = element->GetType();
if (!(newType < kObject)) {
newType = -1;
}
}
}
}
}
if (newType > 0) {
if (element->GetType() >= TStreamerInfo::kObject) {
element->SetNewType(-2);
} else if (element->GetType() != newType) {
element->SetNewType(newType);
if (gDebug > 0) {
Info("BuildOld", "element: %s %s::%s has new type: %s/%d", element->GetTypeName(), GetName(), element->GetName(), dm ? dm->GetFullTypeName() : TDataType::GetTypeName((EDataType)newType), newType);
}
}
} else if (newClass.GetClass()) {
newClass.Reset();
TClass* oldClass = TClass::GetClass(TClassEdit::ShortType(element->GetTypeName(), TClassEdit::kDropTrailStar).c_str());
if (oldClass == newClass.GetClass()) {
} else if (ClassWasMovedToNamespace(oldClass, newClass.GetClass())) {
Int_t oldv;
if (0 != (oldv = ImportStreamerInfo(oldClass, newClass.GetClass()))) {
Warning("BuildOld", "Can not properly load the TStreamerInfo from %s into %s due to a conflict for the class version %d", oldClass->GetName(), newClass->GetName(), oldv);
} else {
element->SetTypeName(newClass->GetName());
if (gDebug > 0) {
Warning("BuildOld", "element: %s::%s %s has new type %s", GetName(), element->GetTypeName(), element->GetName(), newClass->GetName());
}
}
} else if (oldClass == TClonesArray::Class()) {
if (ContainerMatchTClonesArray(newClass.GetClass())) {
Int_t elemType = element->GetType();
Bool_t isPrealloc = (elemType == kObjectp) || (elemType == kAnyp) || (elemType == (kObjectp + kOffsetL)) || (elemType == (kAnyp + kOffsetL));
element->Update(oldClass, newClass.GetClass());
TVirtualCollectionProxy *cp = newClass->GetCollectionProxy();
TConvertClonesArrayToProxy *ms = new TConvertClonesArrayToProxy(cp, element->IsaPointer(), isPrealloc);
element->SetStreamer(ms);
if (element->GetType() == kObject) {
element->SetNewType(kAny);
element->SetType(kAny);
}
if (gDebug > 0) {
Warning("BuildOld","element: %s::%s %s has new type %s", GetName(), element->GetTypeName(), element->GetName(), newClass->GetName());
}
} else {
element->SetNewType(-2);
}
} else if (oldClass && oldClass->GetCollectionProxy() && newClass->GetCollectionProxy()) {
{
TClass *oldFixedClass = FixCollectionV5(GetClass(),oldClass,newClass);
if (oldFixedClass && oldFixedClass != oldClass) {
element->Update(oldClass,oldFixedClass);
oldClass = oldFixedClass;
}
}
if (CollectionMatch(oldClass, newClass)) {
Int_t oldkind = oldClass->GetCollectionType();
Int_t newkind = newClass->GetCollectionType();
if ( (oldkind==ROOT::kSTLmap || oldkind==ROOT::kSTLmultimap) &&
(newkind!=ROOT::kSTLmap && newkind!=ROOT::kSTLmultimap) ) {
Int_t elemType = element->GetType();
Bool_t isPrealloc = (elemType == kObjectp) || (elemType == kAnyp) || (elemType == (kObjectp + kOffsetL)) || (elemType == (kAnyp + kOffsetL));
TClassStreamer *streamer2 = newClass->GetStreamer();
if (streamer2) {
TConvertMapToProxy *ms = new TConvertMapToProxy(streamer2, element->IsaPointer(), isPrealloc);
if (ms && ms->IsValid()) {
element->SetStreamer(ms);
switch( element->GetType() ) {
case TStreamerInfo::kSTLp:
case TStreamerInfo::kSTLp + TStreamerInfo::kOffsetL:
element->SetNewType(-2);
break;
case TStreamerInfo::kSTL:
case TStreamerInfo::kSTL + TStreamerInfo::kOffsetL:
break;
}
} else {
delete ms;
}
}
element->Update(oldClass, newClass.GetClass());
} else if ( (newkind==ROOT::kSTLmap || newkind==ROOT::kSTLmultimap) &&
(oldkind!=ROOT::kSTLmap && oldkind!=ROOT::kSTLmultimap) ) {
element->SetNewType(-2);
} else {
element->Update(oldClass, newClass.GetClass());
}
if (gDebug > 0) {
Warning("BuildOld","element: %s::%s %s has new type %s", GetName(), element->GetTypeName(), element->GetName(), newClass->GetName());
}
} else if (CollectionMatchFloat16(oldClass,newClass)) {
} else if (CollectionMatchDouble32(oldClass,newClass)) {
} else if (CollectionMatchLong64(oldClass,newClass)) {
element->Update(oldClass, newClass.GetClass());
} else if (CollectionMatchULong64(oldClass,newClass)) {
element->Update(oldClass, newClass.GetClass());
} else if (newClass->GetSchemaRules()->HasRuleWithSourceClass( oldClass->GetName() )) {
element->SetNewClass( newClass );
} else {
element->SetNewType(-2);
}
} else if(oldClass &&
newClass.GetClass() &&
newClass->GetSchemaRules() &&
newClass->GetSchemaRules()->HasRuleWithSourceClass( oldClass->GetName() ) ) {
element->SetNewClass( newClass );
} else {
element->SetNewType(-2);
}
Bool_t cannotConvert = kFALSE;
if (element->GetNewType() != -2) {
if (dm) {
if (dm->IsaPointer()) {
if (strncmp(dm->GetTitle(),"->",2)==0) {
if (newClass->IsTObject()) {
newType = kObjectp;
} else if (newClass->GetCollectionProxy()) {
newType = kSTLp;
} else {
newType = kAnyp;
}
} else {
if (TClass::GetClass(dm->GetTypeName())->IsTObject()) {
newType = kObjectP;
} else if (newClass->GetCollectionProxy()) {
newType = kSTLp;
} else {
newType = kAnyP;
}
}
} else {
if (newClass->GetCollectionProxy()) {
newType = kSTL;
} else if (newClass == TString::Class()) {
newType = kTString;
} else if (newClass == TObject::Class()) {
newType = kTObject;
} else if (newClass == TNamed::Class()) {
newType = kTNamed;
} else if (newClass->IsTObject()) {
newType = kObject;
} else {
newType = kAny;
}
}
if ((!dm->IsaPointer() || newType==kSTLp) && dm->GetArrayDim() > 0) {
newType += kOffsetL;
}
} else if (!fClass->IsLoaded()) {
TStreamerInfo* newInfo = (TStreamerInfo*) fClass->GetStreamerInfos()->At(fClass->GetClassVersion());
if (newInfo && (newInfo != this)) {
TStreamerElement* newElems = (TStreamerElement*) newInfo->GetElements()->FindObject(element->GetName());
if (newElems) {
newType = newElems->GetType();
}
} else {
newType = element->GetType();
}
}
if (element->GetType() == kSTL
|| ((element->GetType() == kObject || element->GetType() == kAny || element->GetType() == kObjectp || element->GetType() == kAnyp)
&& oldClass == TClonesArray::Class()))
{
cannotConvert = (newType != kSTL && newType != kObject && newType != kAny && newType != kSTLp && newType != kObjectp && newType != kAnyp);
} else if (element->GetType() == kSTLp || ((element->GetType() == kObjectP || element->GetType() == kAnyP) && oldClass == TClonesArray::Class()) )
{
cannotConvert = (newType != kSTL && newType != kObject && newType != kAny && newType != kSTLp && newType != kObjectP && newType != kAnyP);
} else if (element->GetType() == kSTL + kOffsetL
|| ((element->GetType() == kObject + kOffsetL|| element->GetType() == kAny + kOffsetL|| element->GetType() == kObjectp+ kOffsetL || element->GetType() == kAnyp+ kOffsetL)
&& oldClass == TClonesArray::Class()))
{
cannotConvert = (newType != kSTL + kOffsetL && newType != kObject+ kOffsetL && newType != kAny+ kOffsetL && newType != kSTLp+ kOffsetL && newType != kObjectp+ kOffsetL && newType != kAnyp+ kOffsetL);
} else if (element->GetType() == kSTLp + kOffsetL || ((element->GetType() == kObjectP+ kOffsetL || element->GetType() == kAnyP+ kOffsetL) && oldClass == TClonesArray::Class()) )
{
cannotConvert = (newType != kSTL+ kOffsetL && newType != kObject+ kOffsetL && newType != kAny+ kOffsetL && newType != kSTLp + kOffsetL&& newType != kObjectP+ kOffsetL && newType != kAnyP+ kOffsetL);
} else if ((element->GetType() == kObjectp || element->GetType() == kAnyp
|| element->GetType() == kObject || element->GetType() == kAny
|| element->GetType() == kTObject || element->GetType() == kTNamed || element->GetType() == kTString )) {
if (newType != -1) {
if (newType == kObjectp || newType == kAnyp
|| newType == kObject || newType == kAny
|| newType == kTObject || newType == kTNamed || newType == kTString) {
element->SetNewType(newType);
} else {
cannotConvert = kTRUE;
}
} else {
cannotConvert = kTRUE;
}
} else if (element->GetType() == kObjectP || element->GetType() == kAnyP) {
if (newType != -1) {
if (newType == kObjectP || newType == kAnyP ) {
} else {
cannotConvert = kTRUE;
}
} else {
cannotConvert = kTRUE;
}
}
}
if (cannotConvert) {
element->SetNewType(-2);
if (gDebug > 0) {
Info("BuildOld", "element: %s %s::%s has new type: %s/%d", element->GetTypeName(), GetName(), element->GetName(), dm ? dm->GetFullTypeName() : TDataType::GetTypeName((EDataType)newType), newType);
}
}
} else {
element->SetNewType(-1);
offset = kMissing;
element->SetOffset(kMissing);
}
if (offset != kMissing && fClass->GetState() <= TClass::kEmulated) {
Int_t asize;
if (element->GetType() == TStreamerInfo::kSTL &&
strcmp(element->GetName(),"This") == 0 &&
strcmp(element->GetTypeName(),GetName()) == 0 &&
!fClass->GetCollectionProxy()) {
asize = sizeof(std::vector<int>);
} else {
asize = element->GetSize();
}
if ((offset % sp) != 0) {
offset = offset - (offset % sp) + sp;
}
element->SetOffset(offset);
offset += asize;
}
if (!wasCompiled && rules) {
if (rules->HasRuleWithSource( element->GetName(), kTRUE ) ) {
if (allocClass == 0) {
infoalloc = (TStreamerInfo *)Clone(TString::Format("%s@@%d",GetName(),GetOnFileClassVersion()));
if (!infoalloc) {
Error("BuildOld","Unable to create the StreamerInfo for %s.",TString::Format("%s@@%d",GetName(),GetOnFileClassVersion()).Data());
} else {
infoalloc->SetBit(kBuildOldUsed,false);
infoalloc->BuildCheck();
infoalloc->BuildOld();
allocClass = infoalloc->GetClass();
}
}
if (element->GetNewType()>0
&& !rules->HasRuleWithTarget( element->GetName(), kTRUE ) ) {
TStreamerElement *copy = (TStreamerElement*)element->Clone();
R__TObjArray_InsertBefore( fElements, copy, element );
next();
copy->SetBit(TStreamerElement::kRepeat);
element = copy;
} else {
TStreamerElement *writecopy = (TStreamerElement*)element->Clone();
R__TObjArray_InsertAfter( fElements, writecopy, element );
next();
writecopy->SetBit(TStreamerElement::kWrite);
writecopy->SetNewType( writecopy->GetType() );
writecopy->SetBit(TStreamerElement::kCache);
writecopy->SetOffset(infoalloc ? infoalloc->GetOffset(element->GetName()) : 0);
}
element->SetBit(TStreamerElement::kCache);
element->SetNewType( element->GetType() );
element->SetOffset(infoalloc ? infoalloc->GetOffset(element->GetName()) : 0);
} else if (rules->HasRuleWithTarget( element->GetName(), kTRUE ) ) {
if (element->GetType() == kCounter) {
} else {
element->SetOffset(kMissing);
}
}
} else if (rules && rules->HasRuleWithTarget( element->GetName(), kTRUE ) ) {
if (element->GetType() == kCounter) {
} else {
element->SetOffset(kMissing);
}
}
if (element->GetNewType() == -2) {
Warning("BuildOld", "Cannot convert %s::%s from type: %s to type: %s, skip element", GetName(), element->GetName(), element->GetTypeName(), newClass ? newClass->GetName() : (dm ? dm->GetFullTypeName() : "unknown") );
}
}
if (shouldHaveInfoLoc && fNVirtualInfoLoc==0) {
fNVirtualInfoLoc = 1;
fVirtualInfoLoc = new ULong_t[1];
fVirtualInfoLoc[0] = offset;
offset += sizeof(TStreamerInfo*);
}
if ((fOldVersion <= 2) && nBaze) {
SetBit(kRecovered);
TObjArray& arr = *fElements;
TObjArray tai(nBaze);
int narr = arr.GetLast() + 1;
int iel;
int jel = 0;
int kel = 0;
for (iel = 0; iel < narr; ++iel) {
element = (TStreamerElement*) arr[iel];
if (element->IsBase() && (element->IsA() != TStreamerBase::Class())) {
tai[kel++] = element;
} else {
arr[jel++] = element;
}
}
for (kel = 0; jel < narr;) {
arr[jel++] = tai[kel++];
}
}
if (!wasCompiled) InsertArtificialElements(rules);
if (!wasCompiled && allocClass) {
TStreamerElement *el = new TStreamerArtificial("@@alloc","", 0, TStreamerInfo::kCacheNew, allocClass->GetName());
R__TObjArray_InsertAt( fElements, el, 0 );
el = new TStreamerArtificial("@@dealloc","", 0, TStreamerInfo::kCacheDelete, allocClass->GetName());
fElements->Add( el );
}
Compile();
delete rules;
}
void TStreamerInfo::Clear(Option_t *option)
{
TString opt = option;
opt.ToLower();
if (opt.Contains("build")) {
R__LOCKGUARD2(gInterpreterMutex);
delete [] fComp; fComp = 0;
delete [] fCompFull; fCompFull= 0;
delete [] fCompOpt; fCompOpt = 0;
fNdata = 0;
fNfulldata = 0;
fNslots= 0;
fSize = 0;
ResetIsCompiled();
ResetBit(kBuildOldUsed);
if (fReadObjectWise) fReadObjectWise->fActions.clear();
if (fReadMemberWise) fReadMemberWise->fActions.clear();
if (fReadMemberWiseVecPtr) fReadMemberWiseVecPtr->fActions.clear();
if (fWriteObjectWise) fWriteObjectWise->fActions.clear();
if (fWriteMemberWise) fWriteMemberWise->fActions.clear();
if (fWriteMemberWiseVecPtr) fWriteMemberWiseVecPtr->fActions.clear();
}
}
namespace {
class TMemberInfo {
public:
TClass *fParent;
TString fName;
TString fClassName;
TString fComment;
Int_t fDataType;
TMemberInfo(TClass *parent) : fParent(parent) {};
void SetDataType(Int_t datatype) {
fDataType = datatype;
}
void SetName(const char *name) {
fName = name;
}
void SetClassName(const char *name) {
fClassName = TClassEdit::ResolveTypedef(TClassEdit::ShortType( name, TClassEdit::kDropStlDefault | TClassEdit::kDropStd ).c_str(),kTRUE);
}
void SetComment(const char *title) {
const char *left = strstr(title,"[");
if (left) {
const char *right = strstr(left,"]");
if (right) {
++left;
fComment.Append(left,right-left);
}
}
}
void Clear() {
fName.Clear();
fClassName.Clear();
fComment.Clear();
}
Bool_t operator!=(const TMemberInfo &other) {
if (fName != other.fName) return kTRUE;
if (fDataType < TStreamerInfo::kObject) {
if (fDataType != other.fDataType) {
if ( (fDataType == 4 && other.fDataType == 16)
|| (fDataType == 16 && other.fDataType == 4) ) {
} else if ( (fDataType == 14 && other.fDataType == 17)
|| (fDataType == 17 && other.fDataType == 14) ) {
} else if ( (fDataType == 3 && other.fDataType == 6)
||(fDataType == 6 && other.fDataType == 3) ){
} else {
return kTRUE;
}
}
} else if (fClassName != other.fClassName) {
if ( (fClassName == "long" && (other.fClassName == "long long" || other.fClassName == "Long64_t"))
|| ( (fClassName == "long long" || fClassName == "Long64_t") && other.fClassName == "long") ) {
} else if ( (fClassName == "unsigned long" && (other.fClassName == "unsigned long long" || other.fClassName == "ULong64_t"))
|| ( (fClassName == "unsigned long long" || fClassName == "ULong64_t") && other.fClassName == "unsigned long") ) {
} else if (TClassEdit::IsSTLCont(fClassName)) {
TString name = TClassEdit::ShortType( fClassName, TClassEdit::kDropStlDefault );
TString othername = TClassEdit::ShortType( other.fClassName, TClassEdit::kDropStlDefault );
if (name != othername) {
TClass *cl = TClass::GetClass(name);
TClass *otherCl = TClass::GetClass(othername);
if (!CollectionMatch(cl,otherCl)) {
TClass *oldFixedClass = FixCollectionV5(fParent,cl,otherCl);
if (!oldFixedClass || !CollectionMatch(oldFixedClass,otherCl)) {
return kTRUE;
}
}
}
} else {
return kTRUE;
}
}
return fComment != other.fComment;
}
};
}
void TStreamerInfo::CallShowMembers(const void* obj, TMemberInspector &insp, Bool_t isTransient) const
{
TIter next(fElements);
TStreamerElement* element = (TStreamerElement*) next();
TString elementName;
for (; element; element = (TStreamerElement*) next()) {
if (element->GetOffset() == kMissing) {
continue;
}
char* eaddr = ((char*)obj) + element->GetOffset();
if (element->IsBase()) {
} else if (element->IsaPointer()) {
elementName.Form("*%s",element->GetFullName());
insp.Inspect(fClass, insp.GetParent(), elementName.Data(), eaddr, isTransient);
} else {
insp.Inspect(fClass, insp.GetParent(), element->GetFullName(), eaddr, isTransient);
Int_t etype = element->GetType();
switch(etype) {
case kObject:
case kAny:
case kTObject:
case kTString:
case kTNamed:
case kSTL:
{
TClass *ecl = element->GetClassPointer();
if (ecl && (fClass!=ecl )) {
insp.InspectMember(ecl, eaddr, TString(element->GetName()) + ".", isTransient);
}
break;
}
}
}
}
next.Reset();
element = (TStreamerElement*) next();
for (; element; element = (TStreamerElement*) next()) {
if (element->IsBase()) {
if (element->GetOffset() == kMissing) {
continue;
}
char* eaddr = ((char*)obj) + element->GetOffset();
TClass *ecl = element->GetClassPointer();
if (ecl) {
ecl->CallShowMembers(eaddr, insp, isTransient);
}
}
}
}
TObject *TStreamerInfo::Clone(const char *newname) const
{
TStreamerInfo *newinfo = (TStreamerInfo*)TNamed::Clone(newname);
if (newname && newname[0] && fName != newname) {
TObjArray *newelems = newinfo->GetElements();
Int_t ndata = newelems->GetEntries();
for(Int_t i = 0; i < ndata; ++i) {
TObject *element = newelems->UncheckedAt(i);
if (element->IsA() == TStreamerLoop::Class()) {
TStreamerLoop *eloop = (TStreamerLoop*)element;
if (fName == eloop->GetCountClass()) {
eloop->SetCountClass(newname);
eloop->Init();
}
} else if (element->IsA() == TStreamerBasicPointer::Class()) {
TStreamerBasicPointer *eptr = (TStreamerBasicPointer*)element;
if (fName == eptr->GetCountClass()) {
eptr->SetCountClass(newname);
eptr->Init();
}
}
}
}
return newinfo;
}
Bool_t TStreamerInfo::CompareContent(TClass *cl, TVirtualStreamerInfo *info, Bool_t warn, Bool_t complete, TFile *file)
{
Bool_t result = kTRUE;
R__ASSERT( (cl==0 || info==0) && (cl!=0 || info!=0) );
TString name;
TString type;
TStreamerElement *el;
TStreamerElement *infoel = 0;
TIter next(GetElements());
TIter infonext((TList*)0);
TIter basenext((TList*)0);
TIter membernext((TList*)0);
if (info) {
infonext = info->GetElements();
}
if (cl) {
TList *tlb = cl->GetListOfBases();
if (tlb) {
basenext = tlb;
}
tlb = cl->GetListOfDataMembers();
if (tlb) {
membernext = tlb;
}
}
Bool_t done = kFALSE;
TString localClass;
TString otherClass;
while(!done) {
localClass.Clear();
otherClass.Clear();
el = (TStreamerElement*)next();
if (el && el->IsBase()) {
localClass = el->GetName();
} else {
el = 0;
}
if (cl) {
TBaseClass *tbc = (TBaseClass*)basenext();
if (tbc) {
otherClass = tbc->GetName();
} else if (el==0) {
done = kTRUE;
break;
}
} else {
infoel = (TStreamerElement*)infonext();
if (infoel && infoel->IsBase()) {
otherClass = infoel->GetName();
} else if (el==0) {
done = kTRUE;
break;
}
}
if (TClassEdit::IsSTLCont(localClass)) {
localClass = TClassEdit::ShortType( localClass, TClassEdit::kDropStlDefault );
otherClass = TClassEdit::ShortType( otherClass, TClassEdit::kDropStlDefault );
}
if (localClass != otherClass) {
if (warn) {
if (el==0) {
Warning("CompareContent",
"The in-memory layout version %d for class '%s' has a base class (%s) that the on-file layout version %d does not have.",
GetClassVersion(), GetName(), otherClass.Data(), GetClassVersion());
} else if (otherClass.Length()==0) {
Warning("CompareContent",
"The on-file layout version %d for class '%s' has a base class (%s) that the in-memory layout version %d does not have",
GetClassVersion(), GetName(), localClass.Data(), GetClassVersion());
} else {
Warning("CompareContent",
"One base class of the on-file layout version %d and of the in memory layout version %d for '%s' is different: '%s' vs '%s'",
GetClassVersion(), GetClassVersion(), GetName(), localClass.Data(), otherClass.Data());
}
}
if (!complete) return kFALSE;
result = result && kFALSE;
}
if (cl) {
TStreamerBase *localBase = dynamic_cast<TStreamerBase*>(el);
if (!localBase) continue;
TClass *otherBaseClass = localBase->GetClassPointer();
if (!otherBaseClass) continue;
if (otherBaseClass->IsVersioned() && localBase->GetBaseVersion() != otherBaseClass->GetClassVersion()) {
TString msg;
msg.Form(" The StreamerInfo of class %s read from %s%s\n"
" has the same version (=%d) as the active class but a different checksum.\n"
" You should update the version to ClassDef(%s,%d).\n"
" The objects on this file might not be readable because:\n"
" The in-memory layout version %d for class '%s' has a base class (%s) with version %d but the on-file layout version %d recorded the version number %d for this base class (%s).",
GetName(), file ? "file " : "", file ? file->GetName() : "", fClassVersion, GetName(), fClassVersion + 1,
GetClassVersion(), GetName(), otherClass.Data(), otherBaseClass->GetClassVersion(),
GetClassVersion(), localBase->GetBaseVersion(), localClass.Data());
TStreamerBase *otherBase = (TStreamerBase*)cl->GetStreamerInfo()->GetElements()->FindObject(otherClass);
otherBase->SetErrorMessage(msg);
} else if (!otherBaseClass->IsVersioned() && localBase->GetBaseCheckSum() != otherBaseClass->GetCheckSum()) {
TVirtualStreamerInfo *localBaseInfo = otherBaseClass->FindStreamerInfo(localBase->GetBaseCheckSum());
if (!localBaseInfo) {
const TList *list = file->GetStreamerInfoCache();
localBaseInfo = list ? (TStreamerInfo*)list->FindObject(localBase->GetName()) : 0;
}
if (!localBaseInfo) {
TString msg;
msg.Form(" The StreamerInfo of the base class %s (of class %s) read from %s%s\n"
" refers to a checksum (%x) that can not be found neither in memory nor in the file.\n",
otherBaseClass->GetName(), localClass.Data(),
file ? "file " : "", file ? file->GetName() : "",
localBase->GetBaseCheckSum()
);
TStreamerBase *otherBase = (TStreamerBase*)cl->GetStreamerInfo()->GetElements()->FindObject(otherClass);
otherBase->SetErrorMessage(msg);
continue;
}
if (localBaseInfo->CompareContent(otherBaseClass,0,kFALSE,kFALSE,file) ) {
continue;
}
TString msg;
msg.Form(" The StreamerInfo of class %s read from %s%s\n"
" has the same version (=%d) as the active class but a different checksum.\n"
" You should update the version to ClassDef(%s,%d).\n"
" The objects on this file might not be readable because:\n"
" The in-memory layout version %d for class '%s' has a base class (%s) with checksum %x but the on-file layout version %d recorded the checksum value %x for this base class (%s).",
GetName(), file ? "file " : "", file ? file->GetName() : "", fClassVersion, GetName(), fClassVersion + 1,
GetClassVersion(), GetName(), otherClass.Data(), otherBaseClass->GetCheckSum(),
GetClassVersion(), localBase->GetBaseCheckSum(), localClass.Data());
TStreamerBase *otherBase = (TStreamerBase*)cl->GetStreamerInfo()->GetElements()->FindObject(otherClass);
otherBase->SetErrorMessage(msg);
}
} else {
TStreamerBase *localBase = dynamic_cast<TStreamerBase*>(el);
TStreamerBase *otherBase = dynamic_cast<TStreamerBase*>(infoel);
if (!localBase || !otherBase) continue;
TClass *otherBaseClass = localBase->GetClassPointer();
if (otherBaseClass->IsVersioned() && localBase->GetBaseVersion() != otherBase->GetBaseVersion()) {
TString msg;
msg.Form(" The StreamerInfo of class %s read from %s%s\n"
" has the same version (=%d) as the active class but a different checksum.\n"
" You should update the version to ClassDef(%s,%d).\n"
" The objects on this file might not be readable because:\n"
" The in-memory layout version %d for class '%s' has a base class (%s) with version %d but the on-file layout version %d recorded the version number %d for this base class (%s).",
GetName(), file ? "file " : "", file ? file->GetName() : "", fClassVersion, GetName(), fClassVersion + 1,
GetClassVersion(), GetName(), otherClass.Data(), otherBase->GetBaseVersion(),
GetClassVersion(), localBase->GetBaseVersion(), localClass.Data());
otherBase->SetErrorMessage(msg);
} else if (!otherBaseClass->IsVersioned() && localBase->GetBaseCheckSum() != otherBase->GetBaseCheckSum())
{
TVirtualStreamerInfo *localBaseInfo = otherBaseClass->FindStreamerInfo(localBase->GetBaseCheckSum());
TVirtualStreamerInfo *otherBaseInfo = otherBaseClass->FindStreamerInfo(otherBase->GetBaseCheckSum());
if (localBaseInfo == otherBaseInfo ||
localBaseInfo->CompareContent(0,otherBaseInfo,kFALSE,kFALSE,file) ) {
continue;
}
TString msg;
msg.Form(" The StreamerInfo of class %s read from %s%s\n"
" has the same version (=%d) as the active class but a different checksum.\n"
" You should update the version to ClassDef(%s,%d).\n"
" The objects on this file might not be readable because:\n"
" The in-memory layout version %d for class '%s' has a base class (%s) with checksum %x but the on-file layout version %d recorded the checksum value %x for this base class (%s).",
GetName(), file ? "file " : "", file ? file->GetName() : "", fClassVersion, GetName(), fClassVersion + 1,
GetClassVersion(), GetName(), otherClass.Data(), otherBase->GetBaseCheckSum(),
GetClassVersion(), localBase->GetBaseCheckSum(), localClass.Data());
otherBase->SetErrorMessage(msg);
}
}
}
if (!result && !complete) {
return result;
}
done = kFALSE;
next.Reset();
infonext.Reset();
TMemberInfo local(GetClass());
TMemberInfo other(cl ? cl : info->GetClass());
UInt_t idx = 0;
while(!done) {
local.Clear();
other.Clear();
el = (TStreamerElement*)next();
while (el && (el->IsBase() || el->IsA() == TStreamerArtificial::Class())) {
el = (TStreamerElement*)next();
++idx;
}
if (el) {
local.SetName( el->GetName() );
local.SetClassName( el->GetTypeName() );
local.SetComment( el->GetTitle() );
local.SetDataType( el->GetType() );
}
if (cl) {
TDataMember *tdm = (TDataMember*)membernext();
while(tdm && ( (!tdm->IsPersistent()) || (tdm->Property()&kIsStatic) || (el && local.fName != tdm->GetName()) )) {
tdm = (TDataMember*)membernext();
}
if (tdm) {
other.SetName( tdm->GetName() );
other.SetClassName( tdm->GetTrueTypeName() );
other.SetComment( tdm->GetTitle() );
if (tdm->GetDataType()) {
if (tdm->IsaPointer()) {
if (tdm->GetDataType()->GetType() == TVirtualStreamerInfo::kChar && !tdm->GetArrayDim() && tdm->GetArrayIndex()[0]==0) {
other.SetDataType( TVirtualStreamerInfo::kCharStar );
} else {
other.SetDataType( tdm->GetDataType()->GetType() + TVirtualStreamerInfo::kOffsetP);
}
} else {
if (tdm->GetArrayDim()) {
other.SetDataType( tdm->GetDataType()->GetType() + TVirtualStreamerInfo::kOffsetL);
} else {
other.SetDataType( tdm->GetDataType()->GetType() );
}
}
}
} else if (el==0) {
done = kTRUE;
break;
}
} else {
infoel = (TStreamerElement*)infonext();
while (infoel && (infoel->IsBase() || infoel->IsA() == TStreamerArtificial::Class())) {
infoel = (TStreamerElement*)infonext();
}
if (infoel) {
other.SetName( infoel->GetName() );
other.SetClassName( infoel->GetTypeName() );
other.SetComment( infoel->GetTitle() );
other.SetDataType( infoel->GetType() );
} else if (el==0) {
done = kTRUE;
break;
}
}
if (local!=other) {
if (warn) {
if (!el) {
Warning("CompareContent","The following data member of\nthe in-memory layout version %d of class '%s' is missing from \nthe on-file layout version %d:\n"
" %s %s; //%s"
,GetClassVersion(), GetName(), GetClassVersion()
,other.fClassName.Data(),other.fName.Data(),other.fComment.Data());
} else if (other.fName.Length()==0) {
Warning("CompareContent","The following data member of\nthe in-memory layout version %d of class '%s' is missing from \nthe on-file layout version %d:\n"
" %s %s; //%s"
,GetClassVersion(), GetName(), GetClassVersion()
,local.fClassName.Data(),local.fName.Data(),local.fComment.Data());
} else {
Warning("CompareContent","The following data member of\nthe on-file layout version %d of class '%s' differs from \nthe in-memory layout version %d:\n"
" %s %s; //%s\n"
"vs\n"
" %s %s; //%s"
,GetClassVersion(), GetName(), GetClassVersion()
,local.fClassName.Data(),local.fName.Data(),local.fComment.Data()
,other.fClassName.Data(),other.fName.Data(),other.fComment.Data());
}
}
result = result && kFALSE;
if (!complete) return result;
}
++idx;
}
return result;
}
void TStreamerInfo::ComputeSize()
{
TStreamerElement *element = (TStreamerElement*)fElements->Last();
fSize = element ? element->GetOffset() + element->GetSize() : 0;
if (fNVirtualInfoLoc > 0 && (fVirtualInfoLoc[0]+sizeof(TStreamerInfo*)) >= (ULong_t)fSize) {
fSize = fVirtualInfoLoc[0] + sizeof(TStreamerInfo*);
}
}
void TStreamerInfo::ForceWriteInfo(TFile* file, Bool_t force)
{
if (!file) {
return;
}
TArrayC* cindex = file->GetClassIndex();
if (
(cindex->fArray[fNumber] && !force) ||
(cindex->fArray[fNumber] > 1)
) {
return;
}
static TClassRef string_classref("string");
if (fClass == string_classref) {
return;
}
if (fClass==0) {
if (fElements && fElements->GetEntries()==1 && strcmp("This",fElements->UncheckedAt(0)->GetName())==0) {
return;
}
} else if (fClass->GetCollectionProxy()) {
return;
}
cindex->fArray[fNumber] = 2;
cindex->fArray[0] = 1;
TIter next(fElements);
TStreamerElement* element = (TStreamerElement*) next();
for (; element; element = (TStreamerElement*) next()) {
if (element->IsTransient()) continue;
TClass* cl = element->GetClassPointer();
if (cl) {
TVirtualStreamerInfo* si = 0;
if (cl->Property() & kIsAbstract) {
si = cl->GetCurrentStreamerInfo();
} else {
si = cl->GetStreamerInfo();
}
if (si) {
si->ForceWriteInfo(file, force);
}
}
}
}
TClass *TStreamerInfo::GetActualClass(const void *obj) const
{
R__ASSERT(!fClass->IsLoaded());
if (fNVirtualInfoLoc != 0) {
TStreamerInfo *allocator = *(TStreamerInfo**)( (const char*)obj + fVirtualInfoLoc[0] );
if (allocator) return allocator->GetClass();
}
return (TClass*)fClass;
}
Bool_t TStreamerInfo::MatchLegacyCheckSum(UInt_t checksum) const
{
for(UInt_t i = 1; i < TClass::kLatestCheckSum; ++i) {
if ( checksum == GetCheckSum( (TClass::ECheckSum) i) ) return kTRUE;
}
return kFALSE;
}
UInt_t TStreamerInfo::GetCheckSum(TClass::ECheckSum code) const
{
if (code == TClass::kCurrentCheckSum) code = TClass::kLatestCheckSum;
UInt_t id = 0;
int il;
TString name = GetName();
TString type;
il = name.Length();
for (int i=0; i<il; i++) id = id*3+name[i];
TIter next(GetElements());
TStreamerElement *el;
while ( (el=(TStreamerElement*)next()) && !fClass->GetCollectionProxy()) {
if (el->IsBase()) {
name = el->GetName();
il = name.Length();
for (int i=0; i<il; i++) id = id*3+name[i];
if (code > TClass::kNoBaseCheckSum && el->IsA() == TStreamerBase::Class()) {
TStreamerBase *base = (TStreamerBase*)el;
id = id*3 + base->GetBaseCheckSum();
}
}
}
next.Reset();
while ( (el=(TStreamerElement*)next()) ) {
if (el->IsBase()) continue;
Bool_t isenum = kFALSE;
if ( el->GetType()==3 && gROOT->GetType(el->GetTypeName())==0) {
isenum = kTRUE;
}
if ( (code > TClass::kNoEnum) && isenum) id = id*3 + 1;
name = el->GetName(); il = name.Length();
int i;
for (i=0; i<il; i++) id = id*3+name[i];
if (code == TClass::kReflex || code == TClass::kReflexNoComment) {
type = TClassEdit::ResolveTypedef(el->GetTypeName(),kTRUE);
} else if (code <= TClass::kWithTypeDef) {
type = el->GetTypeName();
} else {
type = TClassEdit::GetLong64_Name(TClassEdit::ResolveTypedef(el->GetTypeName(),kTRUE));
}
if (TClassEdit::IsSTLCont(type)) {
type = TClassEdit::ShortType( type, TClassEdit::kDropStlDefault | TClassEdit::kLong64 );
}
if (code == TClass::kReflex || code == TClass::kReflexNoComment) {
type.ReplaceAll("ULong64_t","unsigned long long");
type.ReplaceAll("Long64_t","long long");
type.ReplaceAll("signed char","char");
type.ReplaceAll("<signed char","<char");
type.ReplaceAll(",signed char",",char");
if (type=="signed char") type = "char";
}
il = type.Length();
for (i=0; i<il; i++) id = id*3+type[i];
int dim = el->GetArrayDim();
if (dim) {
for (i=0;i<dim;i++) id = id*3+el->GetMaxIndex(i);
}
if (code > TClass::kNoRange) {
const char *left;
if (code > TClass::kNoRangeCheck)
left = TVirtualStreamerInfo::GetElementCounterStart(el->GetTitle());
else
left = strstr(el->GetTitle(),"[");
if (left) {
const char *right = strstr(left,"]");
if (right) {
++left;
while (left != right) {
id = id*3 + *left;
++left;
}
}
}
}
}
return id;
}
static void R__WriteConstructorBody(FILE *file, TIter &next)
{
TStreamerElement *element = 0;
next.Reset();
while ((element = (TStreamerElement*)next())) {
if (element->GetType() == TVirtualStreamerInfo::kObjectp || element->GetType() == TVirtualStreamerInfo::kObjectP ||
element->GetType() == TVirtualStreamerInfo::kAnyp || element->GetType() == TVirtualStreamerInfo::kAnyP ||
element->GetType() == TVirtualStreamerInfo::kCharStar || element->GetType() == TVirtualStreamerInfo::kSTLp ||
element->GetType() == TVirtualStreamerInfo::kStreamLoop) {
if(element->GetArrayLength() <= 1) {
fprintf(file," %s = 0;\n",element->GetName());
} else {
fprintf(file," memset(%s,0,%d);\n",element->GetName(),element->GetSize());
}
}
if (TVirtualStreamerInfo::kOffsetP <= element->GetType() && element->GetType() < TVirtualStreamerInfo::kObject ) {
fprintf(file," %s = 0;\n",element->GetName());
}
}
}
static void R__WriteMoveConstructorBody(FILE *file, const TString &protoname, TIter &next)
{
TStreamerElement *element = 0;
next.Reset();
Bool_t atstart = kTRUE;
while ((element = (TStreamerElement*)next())) {
if (element->IsBase()) {
if (atstart) { fprintf(file," : "); atstart = kFALSE; }
else fprintf(file," , ");
fprintf(file, "%s(const_cast<%s &>( rhs ))\n", element->GetName(),protoname.Data());
} else {
if (element->GetArrayLength() <= 1) {
if (atstart) { fprintf(file," : "); atstart = kFALSE; }
else fprintf(file," , ");
fprintf(file, "%s(const_cast<%s &>( rhs ).%s)\n",element->GetName(),protoname.Data(),element->GetName());
}
}
}
fprintf(file,"{\n");
fprintf(file," // This is NOT a copy constructor. This is actually a move constructor (for stl container's sake).\n");
fprintf(file," // Use at your own risk!\n");
fprintf(file," (void)rhs; // avoid warning about unused parameter\n");
next.Reset();
Bool_t defMod = kFALSE;
while ((element = (TStreamerElement*)next())) {
if (element->GetType() == TVirtualStreamerInfo::kObjectp || element->GetType() == TVirtualStreamerInfo::kObjectP||
element->GetType() == TVirtualStreamerInfo::kAnyp || element->GetType() == TVirtualStreamerInfo::kAnyP
|| element->GetType() == TVirtualStreamerInfo::kAnyPnoVT)
{
if (!defMod) { fprintf(file," %s &modrhs = const_cast<%s &>( rhs );\n",protoname.Data(),protoname.Data()); defMod = kTRUE; };
const char *ename = element->GetName();
const char *colon2 = strstr(ename,"::");
if (colon2) ename = colon2+2;
if(element->GetArrayLength() <= 1) {
fprintf(file," modrhs.%s = 0;\n",ename);
} else {
fprintf(file," memset(modrhs.%s,0,%d);\n",ename,element->GetSize());
}
} else {
const char *ename = element->GetName();
if (element->GetType() == kCharStar) {
if (!defMod) {
fprintf(file," %s &modrhs = const_cast<%s &>( rhs );\n",protoname.Data(),protoname.Data()); defMod = kTRUE;
};
fprintf(file," modrhs.%s = 0;\n",ename);
} else if (TVirtualStreamerInfo::kOffsetP <= element->GetType() && element->GetType() < TVirtualStreamerInfo::kObject ) {
if (!defMod) {
fprintf(file," %s &modrhs = const_cast<%s &>( rhs );\n",protoname.Data(),protoname.Data()); defMod = kTRUE;
};
fprintf(file," modrhs.%s = 0;\n",ename);
} else if (element->GetArrayLength() > 1) {
if (element->GetArrayDim() == 1) {
fprintf(file," for (Int_t i=0;i<%d;i++) %s[i] = rhs.%s[i];\n",element->GetArrayLength(),ename,ename);
} else if (element->GetArrayDim() >= 2) {
fprintf(file," for (Int_t i=0;i<%d;i++) (&(%s",element->GetArrayLength(),ename);
for (Int_t d = 0; d < element->GetArrayDim(); ++d) {
fprintf(file,"[0]");
}
fprintf(file,"))[i] = (&(rhs.%s",ename);
for (Int_t d = 0; d < element->GetArrayDim(); ++d) {
fprintf(file,"[0]");
}
fprintf(file,"))[i];\n");
}
} else if (element->GetType() == TVirtualStreamerInfo::kSTLp) {
if (!defMod) { fprintf(file," %s &modrhs = const_cast<%s &>( rhs );\n",protoname.Data(),protoname.Data()); defMod = kTRUE; };
fprintf(file," modrhs.%s = 0;\n",ename);
} else if (element->GetType() == TVirtualStreamerInfo::kSTL) {
if (!defMod) {
fprintf(file," %s &modrhs = const_cast<%s &>( rhs );\n",protoname.Data(),protoname.Data()); defMod = kTRUE;
}
TClass *cle = element->GetClassPointer();
TVirtualCollectionProxy *proxy = cle ? element->GetClassPointer()->GetCollectionProxy() : 0;
std::string method_name = "clear";
if (!element->TestBit(TStreamerElement::kDoNotDelete) && proxy && (((TStreamerSTL*)element)->GetSTLtype() == ROOT::kSTLbitset)) {
method_name = "reset";
}
if (element->IsBase()) {
fprintf(file," modrhs.%s();\n", method_name.c_str());
} else {
fprintf(file," modrhs.%s.%s();\n",ename, method_name.c_str());
}
}
}
}
}
static void R__WriteDestructorBody(FILE *file, TIter &next)
{
TStreamerElement *element = 0;
next.Reset();
while ((element = (TStreamerElement*)next())) {
if (element->GetType() == TVirtualStreamerInfo::kObjectp || element->GetType() == TVirtualStreamerInfo::kObjectP||
element->GetType() == TVirtualStreamerInfo::kAnyp || element->GetType() == TVirtualStreamerInfo::kAnyP
|| element->GetType() == TVirtualStreamerInfo::kAnyPnoVT)
{
const char *ename = element->GetName();
const char *colon2 = strstr(ename,"::");
if (colon2) ename = colon2+2;
if (element->TestBit(TStreamerElement::kDoNotDelete)) {
if(element->GetArrayLength() <= 1) {
fprintf(file," %s = 0;\n",ename);
} else {
fprintf(file," memset(%s,0,%d);\n",ename,element->GetSize());
}
} else {
if(element->GetArrayLength() <= 1) {
fprintf(file," delete %s; %s = 0;\n",ename,ename);
} else {
fprintf(file," for (Int_t i=0;i<%d;i++) delete %s[i]; memset(%s,0,%d);\n",element->GetArrayLength(),ename,ename,element->GetSize());
}
}
}
if (element->GetType() == TVirtualStreamerInfo::kCharStar) {
const char *ename = element->GetName();
if (element->TestBit(TStreamerElement::kDoNotDelete)) {
fprintf(file," %s = 0;\n",ename);
} else {
fprintf(file," delete [] %s; %s = 0;\n",ename,ename);
}
}
if (TVirtualStreamerInfo::kOffsetP <= element->GetType() && element->GetType() < TVirtualStreamerInfo::kObject ) {
const char *ename = element->GetName();
if (element->TestBit(TStreamerElement::kDoNotDelete)) {
fprintf(file," %s = 0;\n",ename);
} else if (element->HasCounter()) {
fprintf(file," delete %s; %s = 0;\n",ename,ename);
} else {
fprintf(file," delete [] %s; %s = 0;\n",ename,ename);
}
}
if (element->GetType() == TVirtualStreamerInfo::kSTL || element->GetType() == TVirtualStreamerInfo::kSTLp) {
const char *ename = element->GetName();
const char *prefix = "";
if ( element->GetType() == TVirtualStreamerInfo::kSTLp ) {
prefix = "*";
} else if ( element->IsBase() ) {
ename = "this";
}
TClass *cle = element->GetClassPointer();
TVirtualCollectionProxy *proxy = cle ? element->GetClassPointer()->GetCollectionProxy() : 0;
if (!element->TestBit(TStreamerElement::kDoNotDelete) && proxy) {
Int_t stltype = ((TStreamerSTL*)element)->GetSTLtype();
if (proxy->HasPointers()) {
fprintf(file," std::for_each( (%s %s).rbegin(), (%s %s).rend(), DeleteObjectFunctor() );\n",prefix,ename,prefix,ename);
} else {
if (stltype == ROOT::kSTLmap || stltype == ROOT::kSTLmultimap) {
TString enamebasic = TMakeProject::UpdateAssociativeToVector(element->GetTypeNameBasic());
std::vector<std::string> inside;
int nestedLoc;
TClassEdit::GetSplit(enamebasic, inside, nestedLoc, TClassEdit::kLong64);
if (inside[1][inside[1].size()-1]=='*' || inside[2][inside[2].size()-1]=='*') {
fprintf(file," std::for_each( (%s %s).rbegin(), (%s %s).rend(), DeleteObjectFunctor() );\n",prefix,ename,prefix,ename);
}
}
}
}
if ( prefix[0] ) {
fprintf(file," delete %s; %s = 0;\n",ename,ename);
}
}
}
}
void TStreamerInfo::GenerateDeclaration(FILE *fp, FILE *sfp, const TList *subClasses, Bool_t top)
{
if (fClassVersion == -3) {
return;
}
Bool_t needGenericTemplate = fElements==0 || fElements->GetEntries() == 0;
Bool_t isTemplate = kFALSE;
const char *clname = GetName();
TString template_protoname;
if (strchr(clname, ':')) {
Int_t len = strlen(clname);
const char *name = clname;
UInt_t nest = 0;
UInt_t pr_pos = 0;
for (Int_t cur = 0; cur < len; ++cur) {
switch (clname[cur]) {
case '<':
++nest;
pr_pos = cur;
isTemplate = kTRUE;
break;
case '>':
if (nest == 0) { cur = len; continue; }
--nest;
break;
case ':': {
if (nest == 0 && clname[cur+1] == ':') {
isTemplate = kFALSE;
name = clname + cur + 2;
}
break;
}
}
}
if (isTemplate) {
template_protoname.Append(clname,pr_pos);
}
clname = name;
} else {
const char *where = strstr(clname, "<");
isTemplate = where != 0;
if (isTemplate) {
template_protoname.Append(clname,where-clname);
}
}
if (needGenericTemplate && isTemplate) {
TString templateName(TMakeProject::GetHeaderName("template "+template_protoname,0));
fprintf(fp, "#ifndef %s_h\n", templateName.Data());
fprintf(fp, "#define %s_h\n", templateName.Data());
}
TString protoname;
UInt_t numberOfNamespaces = TMakeProject::GenerateClassPrefix(fp, GetName(), top, protoname, 0, kFALSE, needGenericTemplate);
TStreamerElement *element;
TIter next(fElements);
Int_t nbase = 0;
while ((element = (TStreamerElement*)next())) {
if (!element->IsBase()) continue;
nbase++;
const char *ename = element->GetName();
if (nbase == 1) fprintf(fp," : public %s",ename);
else fprintf(fp," , public %s",ename);
}
fprintf(fp," {\n");
if (subClasses && subClasses->GetEntries()) {
Bool_t needheader = true;
TIter subnext(subClasses);
TStreamerInfo *subinfo;
Int_t len = strlen(GetName());
while ((subinfo = (TStreamerInfo*)subnext())) {
if (strncmp(GetName(),subinfo->GetName(),len)==0 && (subinfo->GetName()[len]==':') ) {
if (subinfo->GetName()[len+1]==':' && strstr(subinfo->GetName()+len+2,":")==0) {
if (needheader) {
fprintf(fp,"\npublic:\n");
fprintf(fp,"// Nested classes forward declaration.\n");
needheader = false;
}
TString sub_protoname;
UInt_t sub_numberOfClasses = 0;
UInt_t sub_numberOfNamespaces;
if (subinfo->GetClassVersion() == -3) {
sub_numberOfNamespaces = TMakeProject::GenerateClassPrefix(fp, subinfo->GetName() + len+2, kFALSE, sub_protoname, &sub_numberOfClasses, 3);
} else {
sub_numberOfNamespaces = TMakeProject::GenerateClassPrefix(fp, subinfo->GetName() + len+2, kFALSE, sub_protoname, &sub_numberOfClasses, kFALSE);
fprintf(fp, ";\n");
}
for (UInt_t i = 0;i < sub_numberOfClasses;++i) {
fprintf(fp, "}; // end of class.\n");
}
if (sub_numberOfNamespaces > 0) {
Error("GenerateDeclaration","Nested classes %s thought to be inside a namespace inside the class %s",subinfo->GetName(),GetName());
}
}
}
}
}
fprintf(fp,"\npublic:\n");
fprintf(fp,"// Nested classes declaration.\n");
if (subClasses && subClasses->GetEntries()) {
TIter subnext(subClasses,kIterBackward);
TStreamerInfo *subinfo;
Int_t len = strlen(GetName());
while ((subinfo = (TStreamerInfo*)subnext())) {
if (strncmp(GetName(),subinfo->GetName(),len)==0 && (subinfo->GetName()[len]==':')) {
if (subinfo->GetName()[len+1]==':' && strstr(subinfo->GetName()+len+2,":")==0) {
subinfo->GenerateDeclaration(fp, sfp, subClasses, kFALSE);
}
}
}
}
fprintf(fp,"\npublic:\n");
fprintf(fp,"// Data Members.\n");
{
TString name(128);
Int_t ltype = 12;
Int_t ldata = 10;
Int_t lt,ld,is;
TString line;
line.Resize(kMaxLen);
next.Reset();
while ((element = (TStreamerElement*)next())) {
if (element->IsBase()) continue;
const char *ename = element->GetName();
name = ename;
for (Int_t i=0;i < element->GetArrayDim();i++) {
name += TString::Format("[%d]",element->GetMaxIndex(i));
}
name += ";";
ld = name.Length();
TString enamebasic = element->GetTypeNameBasic();
if (element->IsA() == TStreamerSTL::Class()) {
Int_t stltype = ((TStreamerSTL*)element)->GetSTLtype();
switch (stltype) {
case ROOT::kSTLmap:
case ROOT::kSTLmultimap:
case ROOT::kSTLset:
case ROOT::kSTLmultiset:
case ROOT::kSTLunorderedset:
case ROOT::kSTLunorderedmultiset:
{
enamebasic = TMakeProject::UpdateAssociativeToVector(enamebasic);
}
default:
break;
}
}
lt = enamebasic.Length();
line = " ";
line += enamebasic;
if (lt>=ltype) ltype = lt+1;
for (is = 3+lt; is < (3+ltype); ++is) line += ' ';
line += name;
if (element->IsaPointer() && !strchr(line,'*')) line[2+ltype] = '*';
if (ld>=ldata) ldata = ld+1;
for (is = 3+ltype+ld; is < (3+ltype+ldata); ++is) line += ' ';
line += " //";
line += element->GetTitle();
fprintf(fp,"%s\n",line.Data());
}
}
if (needGenericTemplate && isTemplate) {
fprintf(fp,"\n %s() {\n",protoname.Data());
R__WriteConstructorBody(fp,next);
fprintf(fp," }\n");
fprintf(fp," %s(const %s & rhs )\n",protoname.Data(),protoname.Data());
R__WriteMoveConstructorBody(fp,protoname,next);
fprintf(fp," }\n");
fprintf(fp," virtual ~%s() {\n",protoname.Data());
R__WriteDestructorBody(fp,next);
fprintf(fp," }\n\n");
} else {
fprintf(fp,"\n %s();\n",protoname.Data());
fprintf(fp," %s(const %s & );\n",protoname.Data(),protoname.Data());
fprintf(fp," virtual ~%s();\n\n",protoname.Data());
TString guard( TMakeProject::GetHeaderName( GetName(), 0, kTRUE ) );
fprintf(sfp,"#ifndef %s_cxx\n",guard.Data());
fprintf(sfp,"#define %s_cxx\n",guard.Data());
fprintf(sfp,"%s::%s() {\n",GetName(),protoname.Data());
R__WriteConstructorBody(sfp,next);
fprintf(sfp,"}\n");
fprintf(sfp,"%s::%s(const %s & rhs)\n",GetName(),protoname.Data(),protoname.Data());
R__WriteMoveConstructorBody(sfp,protoname,next);
fprintf(sfp,"}\n");
fprintf(sfp,"%s::~%s() {\n",GetName(),protoname.Data());
R__WriteDestructorBody(sfp,next);
fprintf(sfp,"}\n");
fprintf(sfp,"#endif // %s_cxx\n\n",guard.Data());
}
TClass *cl = gROOT->GetClass(GetName());
if (fClassVersion > 1 || (cl && cl->IsTObject()) ) {
if (fClassVersion == 0) {
fprintf(fp," ClassDef(%s,%d); // Generated by MakeProject.\n",protoname.Data(),0);
} else {
fprintf(fp," ClassDef(%s,%d); // Generated by MakeProject.\n",protoname.Data(),fClassVersion + 1);
}
}
fprintf(fp,"};\n");
for(UInt_t i=0;i<numberOfNamespaces;++i) {
fprintf(fp,"} // namespace\n");
}
if (needGenericTemplate && isTemplate) {
fprintf(fp,"#endif // generic template declaration\n");
}
}
UInt_t TStreamerInfo::GenerateIncludes(FILE *fp, char *inclist, const TList *extrainfos)
{
UInt_t ninc = 0;
const char *clname = GetName();
if (strchr(clname,'<')) {
ninc += TMakeProject::GenerateIncludeForTemplate(fp, clname, inclist, kFALSE, extrainfos);
}
TString name(1024);
Int_t ltype = 10;
Int_t ldata = 10;
Int_t lt;
Int_t ld;
TIter next(fElements);
TStreamerElement *element;
Bool_t incRiostream = kFALSE;
while ((element = (TStreamerElement*)next())) {
const char *ename = element->GetName();
const char *colon2 = strstr(ename,"::");
if (colon2) ename = colon2+2;
name = ename;
for (Int_t i=0;i < element->GetArrayDim();i++) {
name += TString::Format("[%d]",element->GetMaxIndex(i));
}
ld = name.Length();
lt = strlen(element->GetTypeName());
if (ltype < lt) ltype = lt;
if (ldata < ld) ldata = ld;
if (!incRiostream && element->InheritsFrom(TStreamerSTL::Class())) {
incRiostream = kTRUE;
TMakeProject::AddInclude( fp, "Riostream.h", kFALSE, inclist);
}
const char *include = element->GetInclude();
if (!include[0]) continue;
Bool_t greater = (include[0]=='<');
include++;
if (strncmp(include,"include/",8)==0) {
include += 8;
}
if (strncmp(include,"include\\",9)==0) {
include += 9;
}
if (strncmp(element->GetTypeName(),"pair<",strlen("pair<"))==0) {
TMakeProject::AddInclude( fp, "utility", kTRUE, inclist);
} else if (strncmp(element->GetTypeName(),"auto_ptr<",strlen("auto_ptr<"))==0) {
TMakeProject::AddInclude( fp, "memory", kTRUE, inclist);
} else {
TString incName( include, strlen(include)-1 );
incName = TMakeProject::GetHeaderName(incName,extrainfos);
TMakeProject::AddInclude( fp, incName.Data(), greater, inclist);
}
if (strchr(element->GetTypeName(),'<')) {
ninc += TMakeProject::GenerateIncludeForTemplate(fp, element->GetTypeName(), inclist, kFALSE, extrainfos);
}
}
if (inclist[0]==0) {
TMakeProject::AddInclude( fp, "TNamed.h", kFALSE, inclist);
}
return ninc;
}
Int_t TStreamerInfo::GenerateHeaderFile(const char *dirname, const TList *subClasses, const TList *extrainfos)
{
if ((fClass && fClass->GetCollectionType()) || TClassEdit::IsSTLCont(GetName())) return 0;
if (strncmp(GetName(),"pair<",strlen("pair<"))==0) return 0;
if (strncmp(GetName(),"auto_ptr<",strlen("auto_ptr<"))==0) return 0;
TClass *cl = TClass::GetClass(GetName());
if (cl) {
if (cl->HasInterpreterInfo()) return 0;
}
Bool_t isTemplate = kFALSE;
if (strchr(GetName(),':')) {
UInt_t len = strlen(GetName());
UInt_t nest = 0;
UInt_t scope = 0;
for(UInt_t i=len; i>0; --i) {
switch(GetName()[i]) {
case '>': ++nest; if (scope==0) { isTemplate = kTRUE; } break;
case '<': --nest; break;
case ':':
if (nest==0 && GetName()[i-1]==':') {
TString nsname(GetName(), i-1);
cl = gROOT->GetClass(nsname);
if (cl && (cl->Size()!=0 || (cl->Size()==0 && !cl->HasInterpreterInfo() ))) {
return 0;
} else if (cl == 0 && extrainfos != 0) {
TStreamerInfo *clinfo = (TStreamerInfo*)extrainfos->FindObject(nsname);
if (clinfo && clinfo->GetClassVersion() == -5) {
return 0;
}
}
++scope;
}
break;
}
}
}
Bool_t needGenericTemplate = isTemplate && (fElements==0 || fElements->GetEntries()==0);
if (gDebug) printf("generating code for class %s\n",GetName());
TString headername( TMakeProject::GetHeaderName( GetName(), extrainfos ) );
TString filename;
filename.Form("%s/%s.h",dirname,headername.Data());
FILE *fp = fopen(filename.Data(),"w");
if (!fp) {
Error("MakeProject","Cannot open output file:%s\n",filename.Data());
return 0;
}
filename.Form("%s/%sProjectHeaders.h",dirname,gSystem->BaseName(dirname));
FILE *allfp = fopen(filename.Data(),"a");
if (!allfp) {
Error("MakeProject","Cannot open output file:%s\n",filename.Data());
fclose(fp);
return 0;
}
fprintf(allfp,"#include \"%s.h\"\n", headername.Data());
fclose(allfp);
char *inclist = new char[50000];
inclist[0] = 0;
TDatime td;
fprintf(fp,"//////////////////////////////////////////////////////////\n");
fprintf(fp,"// This class has been generated by TFile::MakeProject\n");
fprintf(fp,"// (%s by ROOT version %s)\n",td.AsString(),gROOT->GetVersion());
fprintf(fp,"// from the StreamerInfo in file %s\n",gDirectory->GetFile()->GetName());
fprintf(fp,"//////////////////////////////////////////////////////////\n");
fprintf(fp,"\n");
fprintf(fp,"\n");
fprintf(fp,"#ifndef %s_h\n",headername.Data());
fprintf(fp,"#define %s_h\n",headername.Data());
TMakeProject::GenerateForwardDeclaration(fp, GetName(), inclist, kFALSE, needGenericTemplate, extrainfos);
fprintf(fp,"\n");
UInt_t ninc = 0;
ninc += GenerateIncludes(fp, inclist, extrainfos);
if (subClasses) {
TIter subnext(subClasses);
TStreamerInfo *subinfo;
while ((subinfo = (TStreamerInfo*)subnext())) {
ninc = subinfo->GenerateIncludes(fp, inclist, extrainfos);
}
}
fprintf(fp,"\n");
TString sourcename; sourcename.Form( "%s/%sProjectSource.cxx", dirname, gSystem->BaseName(dirname) );
FILE *sfp = fopen( sourcename.Data(), "a" );
if (sfp) {
GenerateDeclaration(fp, sfp, subClasses);
} else {
Error("GenerateHeaderFile","Could not open %s for appending",sourcename.Data());
}
TMakeProject::GeneratePostDeclaration(fp, this, inclist);
fprintf(fp,"#endif\n");
delete [] inclist;
fclose(fp);
if (sfp) fclose(sfp);
return 1;
}
Int_t TStreamerInfo::GetDataMemberOffset(TDataMember *dm, TMemberStreamer *&streamer) const
{
TIter nextr(fClass->GetListOfRealData());
char dmbracket[256];
snprintf(dmbracket,255,"%s[",dm->GetName());
Int_t offset = kMissing;
if (!fClass->IsLoaded()) {
if (! (dm->Property() & kIsStatic) ) {
offset = dm->GetOffset();
}
}
TRealData *rdm;
while ((rdm = (TRealData*)nextr())) {
char *rdmc = (char*)rdm->GetName();
if (dm->IsaPointer() && rdmc[0] == '*') rdmc++;
if (rdm->GetDataMember() != dm) continue;
if (strcmp(rdmc,dm->GetName()) == 0) {
offset = rdm->GetThisOffset();
streamer = rdm->GetStreamer();
break;
}
if (strcmp(rdm->GetName(),dm->GetName()) == 0) {
if (rdm->IsObject()) {
offset = rdm->GetThisOffset();
streamer = rdm->GetStreamer();
break;
}
}
if (strstr(rdm->GetName(),dmbracket)) {
offset = rdm->GetThisOffset();
streamer = rdm->GetStreamer();
break;
}
}
return offset;
}
Int_t TStreamerInfo::GetOffset(const char *elementName) const
{
if (elementName == 0) return 0;
Int_t offset = 0;
TStreamerElement *elem = (TStreamerElement*)fElements->FindObject(elementName);
if (elem) offset = elem->GetOffset();
return offset;
}
Int_t TStreamerInfo::GetSize() const
{
return fSize;
}
Int_t TStreamerInfo::GetSizeElements() const
{
TIter next(fElements);
TStreamerElement *element;
Int_t asize = 0;
while ((element = (TStreamerElement*)next())) {
asize += element->GetSize();
}
return asize;
}
TStreamerElement* TStreamerInfo::GetStreamerElement(const char* datamember, Int_t& offset) const
{
if (!fElements) {
return 0;
}
TStreamerElement* element = (TStreamerElement*) fElements->FindObject(datamember);
if (element) {
offset = element->GetOffset();
return element;
}
if (fClass->HasDataMemberInfo()) {
TStreamerElement* base_element = 0;
TBaseClass* base = 0;
TClass* base_cl = 0;
Int_t base_offset = 0;
Int_t local_offset = 0;
TIter nextb(fClass->GetListOfBases());
while ((base = (TBaseClass*) nextb())) {
base_cl = TClass::GetClass(base->GetName());
base_element = (TStreamerElement*) fElements->FindObject(base->GetName());
if (!base_cl || !base_element) {
continue;
}
base_offset = base_element->GetOffset();
element = ((TStreamerInfo*)base_cl->GetStreamerInfo())->GetStreamerElement(datamember, local_offset);
if (element) {
offset = base_offset + local_offset;
return element;
}
}
} else {
TIter next(fElements);
TStreamerElement* curelem = 0;
while ((curelem = (TStreamerElement*) next())) {
if (curelem->InheritsFrom(TStreamerBase::Class())) {
TClass* baseClass = curelem->GetClassPointer();
if (!baseClass) {
continue;
}
Int_t base_offset = curelem->GetOffset();
Int_t local_offset = 0;
TStreamerInfo *baseInfo;
if (baseClass->Property() & kIsAbstract) {
baseInfo = (TStreamerInfo*)baseClass->GetStreamerInfoAbstractEmulated();
} else {
baseInfo = (TStreamerInfo*)baseClass->GetStreamerInfo();
}
if (baseInfo) element = baseInfo->GetStreamerElement(datamember, local_offset);
if (element) {
offset = base_offset + local_offset;
return element;
}
}
}
}
return 0;
}
TStreamerElement* TStreamerInfo::GetStreamerElementReal(Int_t i, Int_t j) const
{
::Obsolete("TStreamerInfo::GetStreamerElementReal", "v5-34-20", "v6-00-02");
if (i < 0 || i >= fNdata) return 0;
if (j < 0) return 0;
if (!fElements) return 0;
TStreamerElement *se = (TStreamerElement*)fCompOpt[i]->fElem;
if (!se) return 0;
Int_t nelems = fElements->GetEntriesFast();
for (Int_t ise=0;ise < nelems;ise++) {
if (se != (TStreamerElement*)fElements->UncheckedAt(ise)) continue;
if (ise+j >= nelems) return 0;
return (TStreamerElement*)fElements->UncheckedAt(ise+j);
}
return 0;
}
template <typename T>
T TStreamerInfo::GetTypedValueAux(Int_t type, void *ladd, Int_t k, Int_t len)
{
if (type>=kConv && type<kSTL) {
type -= kConv;
}
switch (type) {
case kBool: {Bool_t *val = (Bool_t*)ladd; return T(*val);}
case kChar: {Char_t *val = (Char_t*)ladd; return T(*val);}
case kShort: {Short_t *val = (Short_t*)ladd; return T(*val);}
case kInt: {Int_t *val = (Int_t*)ladd; return T(*val);}
case kLong: {Long_t *val = (Long_t*)ladd; return T(*val);}
case kLong64: {Long64_t *val = (Long64_t*)ladd; return T(*val);}
case kFloat: {Float_t *val = (Float_t*)ladd; return T(*val);}
case kFloat16: {Float_t *val = (Float_t*)ladd; return T(*val);}
case kDouble: {Double_t *val = (Double_t*)ladd; return T(*val);}
case kDouble32: {Double_t *val = (Double_t*)ladd; return T(*val);}
case kUChar: {UChar_t *val = (UChar_t*)ladd; return T(*val);}
case kUShort: {UShort_t *val = (UShort_t*)ladd; return T(*val);}
case kUInt: {UInt_t *val = (UInt_t*)ladd; return T(*val);}
case kULong: {ULong_t *val = (ULong_t*)ladd; return T(*val);}
#if defined(_MSC_VER) && (_MSC_VER <= 1200)
case kULong64: {Long64_t *val = (Long64_t*)ladd; return T(*val);}
#else
case kULong64: {ULong64_t *val= (ULong64_t*)ladd; return T(*val);}
#endif
case kBits: {UInt_t *val = (UInt_t*)ladd; return T(*val);}
case kOffsetL + kBool: {Bool_t *val = (Bool_t*)ladd; return T(val[k]);}
case kOffsetL + kChar: {Char_t *val = (Char_t*)ladd; return T(val[k]);}
case kOffsetL + kShort: {Short_t *val = (Short_t*)ladd; return T(val[k]);}
case kOffsetL + kInt: {Int_t *val = (Int_t*)ladd; return T(val[k]);}
case kOffsetL + kLong: {Long_t *val = (Long_t*)ladd; return T(val[k]);}
case kOffsetL + kLong64: {Long64_t *val = (Long64_t*)ladd; return T(val[k]);}
case kOffsetL + kFloat: {Float_t *val = (Float_t*)ladd; return T(val[k]);}
case kOffsetL + kFloat16: {Float_t *val = (Float_t*)ladd; return T(val[k]);}
case kOffsetL + kDouble: {Double_t *val = (Double_t*)ladd; return T(val[k]);}
case kOffsetL + kDouble32:{Double_t *val = (Double_t*)ladd; return T(val[k]);}
case kOffsetL + kUChar: {UChar_t *val = (UChar_t*)ladd; return T(val[k]);}
case kOffsetL + kUShort: {UShort_t *val = (UShort_t*)ladd; return T(val[k]);}
case kOffsetL + kUInt: {UInt_t *val = (UInt_t*)ladd; return T(val[k]);}
case kOffsetL + kULong: {ULong_t *val = (ULong_t*)ladd; return T(val[k]);}
#if defined(_MSC_VER) && (_MSC_VER <= 1200)
case kOffsetL + kULong64: {Long64_t *val = (Long64_t*)ladd; return T(val[k]);}
#else
case kOffsetL + kULong64:{ULong64_t *val= (ULong64_t*)ladd; return T(val[k]);}
#endif
#define READ_ARRAY(TYPE_t) \
{ \
Int_t sub_instance, index; \
Int_t instance = k; \
if (len) { \
index = instance / len; \
sub_instance = instance % len; \
} else { \
index = instance; \
sub_instance = 0; \
} \
TYPE_t **val =(TYPE_t**)(ladd); \
return T((val[sub_instance])[index]); \
}
case kOffsetP + kBool_t: READ_ARRAY(Bool_t)
case kOffsetP + kChar_t: READ_ARRAY(Char_t)
case kOffsetP + kShort_t: READ_ARRAY(Short_t)
case kOffsetP + kInt_t: READ_ARRAY(Int_t)
case kOffsetP + kLong_t: READ_ARRAY(Long_t)
case kOffsetP + kLong64_t: READ_ARRAY(Long64_t)
case kOffsetP + kFloat16_t:
case kOffsetP + kFloat_t: READ_ARRAY(Float_t)
case kOffsetP + kDouble32_t:
case kOffsetP + kDouble_t: READ_ARRAY(Double_t)
case kOffsetP + kUChar_t: READ_ARRAY(UChar_t)
case kOffsetP + kUShort_t: READ_ARRAY(UShort_t)
case kOffsetP + kUInt_t: READ_ARRAY(UInt_t)
case kOffsetP + kULong_t: READ_ARRAY(ULong_t)
#if defined(_MSC_VER) && (_MSC_VER <= 1200)
case kOffsetP + kULong64_t: READ_ARRAY(Long64_t)
#else
case kOffsetP + kULong64_t: READ_ARRAY(ULong64_t)
#endif
case kCounter: {Int_t *val = (Int_t*)ladd; return T(*val);}
}
return 0;
}
template Double_t TStreamerInfo::GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const;
template Long64_t TStreamerInfo::GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const;
template LongDouble_t TStreamerInfo::GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const;
template <typename T>
T TStreamerInfo::GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const
{
char *ladd;
Int_t atype;
if (len >= 0) {
ladd = pointer;
atype = i;
} else {
if (i < 0) return 0;
ladd = pointer + fCompFull[i]->fOffset;
atype = fCompFull[i]->fNewType;
len = fCompFull[i]->fElem->GetArrayLength();
if (atype == kSTL) {
TClass *newClass = fCompFull[i]->fElem->GetNewClass();
if (newClass == 0) {
newClass = fCompFull[i]->fElem->GetClassPointer();
}
TClass *innerClass = newClass->GetCollectionProxy()->GetValueClass();
if (innerClass) {
return 0;
} else {
TVirtualCollectionProxy *proxy = newClass->GetCollectionProxy();
atype = (TStreamerInfo::EReadWrite)proxy->GetType();
TVirtualCollectionProxy::TPushPop pop(proxy,ladd);
Int_t nc = proxy->Size();
if (j >= nc) return 0;
char *element_ptr = (char*)proxy->At(j);
return GetTypedValueAux<T>(atype,element_ptr,0,1);
}
}
}
return GetTypedValueAux<T>(atype,ladd,j,len);
}
template Double_t TStreamerInfo::GetTypedValueClones<Double_t>(TClonesArray *clones, Int_t i, Int_t j, int k, Int_t eoffset) const;
template Long64_t TStreamerInfo::GetTypedValueClones(TClonesArray *clones, Int_t i, Int_t j, int k, Int_t eoffset) const;
template LongDouble_t TStreamerInfo::GetTypedValueClones(TClonesArray *clones, Int_t i, Int_t j, int k, Int_t eoffset) const;
template <typename T>
T TStreamerInfo::GetTypedValueClones(TClonesArray *clones, Int_t i, Int_t j, int k, Int_t eoffset) const
{
Int_t nc = clones->GetEntriesFast();
if (j >= nc) return 0;
char *pointer = (char*)clones->UncheckedAt(j);
char *ladd = pointer + eoffset + fCompFull[i]->fOffset;
return GetTypedValueAux<T>(fCompFull[i]->fType,ladd,k,((TStreamerElement*)fCompFull[i]->fElem)->GetArrayLength());
}
template Double_t TStreamerInfo::GetTypedValueSTL(TVirtualCollectionProxy *cont, Int_t i, Int_t j, int k, Int_t eoffset) const;
template Long64_t TStreamerInfo::GetTypedValueSTL(TVirtualCollectionProxy *cont, Int_t i, Int_t j, int k, Int_t eoffset) const;
template LongDouble_t TStreamerInfo::GetTypedValueSTL(TVirtualCollectionProxy *cont, Int_t i, Int_t j, int k, Int_t eoffset) const;
template <typename T>
T TStreamerInfo::GetTypedValueSTL(TVirtualCollectionProxy *cont, Int_t i, Int_t j, int k, Int_t eoffset) const
{
Int_t nc = cont->Size();
if (j >= nc) return 0;
char *pointer = (char*)cont->At(j);
char *ladd = pointer + eoffset + fCompFull[i]->fOffset;
return GetTypedValueAux<T>(fCompFull[i]->fType,ladd,k,((TStreamerElement*)fCompFull[i]->fElem)->GetArrayLength());
}
template Double_t TStreamerInfo::GetTypedValueSTLP(TVirtualCollectionProxy *cont, Int_t i, Int_t j, int k, Int_t eoffset) const;
template Long64_t TStreamerInfo::GetTypedValueSTLP(TVirtualCollectionProxy *cont, Int_t i, Int_t j, int k, Int_t eoffset) const;
template LongDouble_t TStreamerInfo::GetTypedValueSTLP(TVirtualCollectionProxy *cont, Int_t i, Int_t j, int k, Int_t eoffset) const;
template <typename T>
T TStreamerInfo::GetTypedValueSTLP(TVirtualCollectionProxy *cont, Int_t i, Int_t j, int k, Int_t eoffset) const
{
Int_t nc = cont->Size();
if (j >= nc) return 0;
char **ptr = (char**)cont->At(j);
char *pointer = *ptr;
char *ladd = pointer + eoffset + fCompFull[i]->fOffset;
return GetTypedValueAux<T>(fCompFull[i]->fType,ladd,k,((TStreamerElement*)fCompFull[i]->fElem)->GetArrayLength());
}
void TStreamerInfo::InsertArtificialElements(const TObjArray *rules)
{
if (!rules) return;
TIter next(fElements);
UInt_t count = 0;
for(Int_t art = 0; art < rules->GetEntries(); ++art) {
ROOT::TSchemaRule *rule = (ROOT::TSchemaRule*)rules->At(art);
if( rule->IsRenameRule() || rule->IsAliasRule() )
continue;
next.Reset();
TStreamerElement *element;
while ((element = (TStreamerElement*) next())) {
if ( rule->HasTarget( element->GetName() ) ) {
if ( rule->GetAttributes()[0] != 0 ) {
TString attr( rule->GetAttributes() );
attr.ToLower();
if (attr.Contains("owner")) {
if (attr.Contains("notowner")) {
element->SetBit(TStreamerElement::kDoNotDelete);
} else {
element->ResetBit(TStreamerElement::kDoNotDelete);
}
}
}
break;
}
}
const TObjArray *sources = rule->GetSource();
TIter input(sources);
TObject *src;
while((src = input())) {
if ( !GetElements()->FindObject(src->GetName()) ) {
#if 0 // Don't warn about not activating the rule. If don't warn the user can
TString ruleStr;
rule->AsString(ruleStr);
Warning("InsertArtificialElements","For class %s in StreamerInfo %d is missing the source data member %s when trying to apply the rule:\n %s",
GetName(),GetClassVersion(),src->GetName(),ruleStr.Data());
rule = 0;
#endif
break;
}
}
if (!rule) continue;
TStreamerArtificial *newel;
typedef std::vector<TStreamerArtificial*> vec_t;
vec_t toAdd;
if (rule->GetTarget()==0) {
TString newName;
newName.Form("%s_rule%d",fClass->GetName(),count);
newel = new TStreamerArtificial(newName,"",
fClass->GetDataMemberOffset(newName),
TStreamerInfo::kArtificial,
"void");
newel->SetBit(TStreamerElement::kWholeObject);
newel->SetReadFunc( rule->GetReadFunctionPointer() );
newel->SetReadRawFunc( rule->GetReadRawFunctionPointer() );
toAdd.push_back(newel);
} else {
toAdd.reserve(rule->GetTarget()->GetEntries());
TObjString * objstr = (TObjString*)(rule->GetTarget()->At(0));
if (objstr) {
TString newName = objstr->String();
TString realDataName;
if ( TDataMember* dm = fClass->GetDataMember( newName ) ) {
TRealData::GetName(realDataName,dm);
newel = new TStreamerArtificial(realDataName,"",
fClass->GetDataMemberOffset(newName),
TStreamerInfo::kArtificial,
fClass->GetDataMember( newName )->GetTypeName());
newel->SetReadFunc( rule->GetReadFunctionPointer() );
newel->SetReadRawFunc( rule->GetReadRawFunctionPointer() );
toAdd.push_back(newel);
} else {
}
for(Int_t other = 1; other < rule->GetTarget()->GetEntries(); ++other) {
objstr = (TObjString*)(rule->GetTarget()->At(other));
if (objstr) {
newName = objstr->String();
if ( TDataMember* dm = fClass->GetDataMember( newName ) ) {
TRealData::GetName(realDataName,dm);
newel = new TStreamerArtificial(realDataName,"",
fClass->GetDataMemberOffset(newName),
TStreamerInfo::kArtificial,
fClass->GetDataMember( newName )->GetTypeName());
toAdd.push_back(newel);
}
}
}
}
}
TIter s_iter(rule->GetSource());
Int_t loc = -1;
while( TObjString *s = (TObjString*)s_iter() ) {
for(Int_t i = fElements->GetLast(); i >= 0 && (i+1) >= loc; --i) {
if (s->String() == fElements->UncheckedAt(i)->GetName()) {
if (loc == -1 || (i+1)>loc) {
loc = i+1;
}
}
}
}
if (loc == -1) {
for(Int_t i = fElements->GetLast(); i >= 0 && (i+1) >= loc; --i) {
if ( ((TStreamerElement*)fElements->UncheckedAt(i))->GetNewType() != -2 ) {
break;
}
loc = i;
}
}
if (loc == -1) {
for(vec_t::iterator iter = toAdd.begin(); iter != toAdd.end(); ++iter) {
fElements->Add(*iter);
}
} else {
R__TObjArray_InsertAt(fElements, toAdd, loc);
}
}
}
void TStreamerInfo::ls(Option_t *option) const
{
if (fClass && (fName != fClass->GetName())) {
if (fClass->IsVersioned()) {
Printf("\nStreamerInfo for conversion to %s from: %s, version=%d, checksum=0x%x",fClass->GetName(),GetName(),fClassVersion,GetCheckSum());
} else {
Printf("\nStreamerInfo for conversion to %s from: %s, checksum=0x%x",fClass->GetName(),GetName(),GetCheckSum());
}
} else {
if (!fClass || fClass->IsVersioned()) {
Printf("\nStreamerInfo for class: %s, version=%d, checksum=0x%x",GetName(),fClassVersion,GetCheckSum());
} else {
Printf("\nStreamerInfo for class: %s, checksum=0x%x",GetName(),GetCheckSum());
}
}
if (fElements) {
TIter next(fElements);
TObject *obj;
while ((obj = next()))
obj->ls(option);
}
if (strstr(option,"full") != 0) {
for (Int_t i=0; i < fNfulldata; ++i) {
TStreamerElement *element = (TStreamerElement*)fCompFull[i]->fElem;
TString sequenceType;
element->GetSequenceType(sequenceType);
if (sequenceType.Length()) {
sequenceType.Prepend(" [");
sequenceType += "]";
}
Printf(" i=%2d, %-15s type=%3d, offset=%3d, len=%d, method=%ld%s",
i,element->GetName(),fCompFull[i]->fType,fCompFull[i]->fOffset,fCompFull[i]->fLength,fCompFull[i]->fMethod,
sequenceType.Data());
}
} else {
Bool_t wantOrig = strstr(option,"incOrig") != 0;
Bool_t optimized = kFALSE;
for (Int_t i=0,j=0;i < fNdata;++i,++j) {
TStreamerElement *element = (TStreamerElement*)fCompOpt[i]->fElem;
TString sequenceType;
element->GetSequenceType(sequenceType);
optimized = TStreamerInfo::kOffsetL < fCompOpt[i]->fType && fCompOpt[i]->fType < TStreamerInfo::kOffsetP && fCompOpt[i]->fLength > fCompOpt[i]->fElem->GetArrayLength();
if (optimized) {
if (sequenceType.Length() != 0) {
sequenceType += ',';
}
sequenceType += "optimized";
}
if (sequenceType.Length()) {
sequenceType.Prepend(" [");
sequenceType += "]";
}
Printf(" i=%2d, %-15s type=%3d, offset=%3d, len=%d, method=%ld%s",
i,element->GetName(),fCompOpt[i]->fType,fCompOpt[i]->fOffset,fCompOpt[i]->fLength,fCompOpt[i]->fMethod,
sequenceType.Data());
if (optimized && wantOrig) {
Bool_t done;
do {
element = (TStreamerElement*)fCompFull[j]->fElem;
element->GetSequenceType(sequenceType);
if (sequenceType.Length()) {
sequenceType.Prepend(" [");
sequenceType += "]";
}
Printf(" j=%2d, %-15s type=%3d, offset=%3d, len=%d, method=%ld%s",
j,element->GetName(),fCompFull[j]->fType,fCompFull[j]->fOffset,fCompFull[j]->fLength,fCompFull[j]->fMethod,
sequenceType.Data());
++j;
done = j >= fNfulldata || ( (i+1 < fNdata) && fCompOpt[i+1]->fElem == fCompFull[j+1]->fElem );
} while (!done);
}
}
}
}
void* TStreamerInfo::New(void *obj)
{
char* p = (char*) obj;
TIter next(fElements);
if (!p) {
p = new char[fSize];
memset(p, 0, fSize);
}
next.Reset();
TStreamerElement* element = (TStreamerElement*) next();
for (; element; element = (TStreamerElement*) next()) {
if (element->GetOffset() == kMissing) {
continue;
}
TClass* cle = element->GetClassPointer();
if (!cle) {
continue;
}
char* eaddr = p + element->GetOffset();
Int_t etype = element->GetType();
switch (etype) {
case kAnyP:
case kObjectP:
case kSTLp:
{
char** r = (char**) eaddr;
Int_t len = element->GetArrayLength();
for (Int_t i = 0; i < len; ++i) {
r[i] = 0;
}
}
break;
case kObjectp:
case kAnyp:
{
if (cle != TClonesArray::Class()) {
void** r = (void**) eaddr;
*r = cle->New();
} else {
const char* title = element->GetTitle();
const char* bracket1 = strrchr(title, '(');
const char* bracket2 = strrchr(title, ')');
if (bracket1 && bracket2 && (bracket2 != (bracket1 + 1))) {
Int_t len = bracket2 - (bracket1 + 1);
char* clonesClass = new char[len+1];
clonesClass[0] = '\0';
strncat(clonesClass, bracket1 + 1, len);
void** r = (void**) eaddr;
*r = (void*) new TClonesArray(clonesClass);
delete[] clonesClass;
} else {
void** r = (void**) eaddr;
*r = (void*) new TClonesArray();
}
}
}
break;
case kBase:
{
if (cle->Property() & kIsAbstract) {
TVirtualStreamerInfo *einfo = cle->GetStreamerInfoAbstractEmulated();
if (einfo) einfo->New(eaddr);
} else {
cle->New(eaddr);
}
break;
}
case kObject:
case kAny:
case kTObject:
case kTString:
case kTNamed:
{
cle->New(eaddr);
}
break;
case kSTL:
{
if (strcmp(element->GetName(),"This")==0 &&
!cle->GetCollectionProxy()) {
} else {
cle->New(eaddr);
}
}
break;
case kObject + kOffsetL:
case kAny + kOffsetL:
case kTObject + kOffsetL:
case kTString + kOffsetL:
case kTNamed + kOffsetL:
case kSTL + kOffsetL:
{
Int_t size = cle->Size();
char* r = eaddr;
Int_t len = element->GetArrayLength();
for (Int_t i = 0; i < len; ++i, r += size) {
cle->New(r);
}
}
break;
}
}
for(int nbase = 0; nbase < fNVirtualInfoLoc; ++nbase) {
*(TStreamerInfo**)(p + fVirtualInfoLoc[nbase]) = this;
}
++fLiveCount;
return p;
}
void* TStreamerInfo::NewArray(Long_t nElements, void *ary)
{
if (fClass == 0) {
Error("NewArray", "TClass pointer is null!");
return 0;
}
Int_t size = fClass->Size();
char* p = (char*) ary;
if (!p) {
Long_t len = nElements * size + sizeof(Long_t)*2;
p = new char[len];
memset(p, 0, len);
}
Long_t* r = (Long_t*) p;
r[0] = size;
r[1] = nElements;
char* dataBegin = (char*) &r[2];
p = dataBegin;
for (Long_t cnt = 0; cnt < nElements; ++cnt) {
New(p);
p += size;
}
return dataBegin;
}
#define DeleteBasicPointer(addr,element,name) \
{ \
name **f = (name**)(addr); \
int n = element->GetArrayLength() ? element->GetArrayLength() : 1;\
for(int j=0;j<n;j++) { \
delete [] f[j]; \
f[j] = 0; \
} \
}
void TStreamerInfo::DestructorImpl(void* obj, Bool_t dtorOnly)
{
R__ASSERT(obj != 0);
char *p = (char*)obj;
Int_t nelements = fElements->GetEntriesFast();
for (Int_t elenum = nelements - 1; elenum >= 0; --elenum) {
TStreamerElement* ele = (TStreamerElement*) fElements->UncheckedAt(elenum);
if (ele->GetOffset() == kMissing) continue;
char* eaddr = p + ele->GetOffset();
Int_t etype = ele->GetType();
switch(etype) {
case TStreamerInfo::kOffsetP + TStreamerInfo::kBool: DeleteBasicPointer(eaddr,ele,Bool_t); continue;
case TStreamerInfo::kOffsetP + TStreamerInfo::kChar: DeleteBasicPointer(eaddr,ele,Char_t); continue;
case TStreamerInfo::kOffsetP + TStreamerInfo::kShort: DeleteBasicPointer(eaddr,ele,Short_t); continue;
case TStreamerInfo::kOffsetP + TStreamerInfo::kInt: DeleteBasicPointer(eaddr,ele,Int_t); continue;
case TStreamerInfo::kOffsetP + TStreamerInfo::kLong: DeleteBasicPointer(eaddr,ele,Long_t); continue;
case TStreamerInfo::kOffsetP + TStreamerInfo::kLong64: DeleteBasicPointer(eaddr,ele,Long64_t); continue;
case TStreamerInfo::kOffsetP + TStreamerInfo::kFloat16:
case TStreamerInfo::kOffsetP + TStreamerInfo::kFloat: DeleteBasicPointer(eaddr,ele,Float_t); continue;
case TStreamerInfo::kOffsetP + TStreamerInfo::kDouble32:
case TStreamerInfo::kOffsetP + TStreamerInfo::kDouble: DeleteBasicPointer(eaddr,ele,Double_t); continue;
case TStreamerInfo::kOffsetP + TStreamerInfo::kUChar: DeleteBasicPointer(eaddr,ele,UChar_t); continue;
case TStreamerInfo::kOffsetP + TStreamerInfo::kUShort: DeleteBasicPointer(eaddr,ele,UShort_t); continue;
case TStreamerInfo::kOffsetP + TStreamerInfo::kUInt: DeleteBasicPointer(eaddr,ele,UInt_t); continue;
case TStreamerInfo::kOffsetP + TStreamerInfo::kULong: DeleteBasicPointer(eaddr,ele,ULong_t); continue;
case TStreamerInfo::kOffsetP + TStreamerInfo::kULong64:DeleteBasicPointer(eaddr,ele,ULong64_t); continue;
}
TClass* cle = ele->GetClassPointer();
if (!cle) continue;
if (etype == kObjectp || etype == kAnyp) {
Int_t len = ele->GetArrayLength();
if (!len) {
len = 1;
}
void** r = (void**) eaddr;
for (Int_t j = len - 1; j >= 0; --j) {
if (r[j]) {
cle->Destructor(r[j]);
r[j] = 0;
}
}
}
if ((etype == kObjectP || etype == kAnyP || etype == kSTLp) && !ele->TestBit(TStreamerElement::kDoNotDelete)) {
Int_t len = ele->GetArrayLength();
if (!len) {
len = 1;
}
void** r = (void**) eaddr;
for (Int_t j = len - 1; j >= 0; --j) {
if (r[j]) {
cle->Destructor(r[j]);
r[j] = 0;
}
}
}
if (etype == kBase) {
if (cle->Property() & kIsAbstract) {
TVirtualStreamerInfo *einfo = cle->GetStreamerInfoAbstractEmulated();
if (einfo) einfo->Destructor(eaddr, kTRUE);
} else {
cle->Destructor(eaddr, kTRUE);
}
}
if (etype == kObject || etype == kAny ||
etype == kTObject || etype == kTString || etype == kTNamed) {
cle->Destructor(eaddr, kTRUE);
}
if (etype == kSTL) {
TVirtualCollectionProxy *pr = cle->GetCollectionProxy();
if (!pr) {
if (strcmp(ele->GetName(),"This")==0) {
} else {
cle->Destructor(eaddr, kTRUE);
}
} else {
if (ele->TestBit(TStreamerElement::kDoNotDelete)) {
TVirtualCollectionProxy::TPushPop env(cle->GetCollectionProxy(), eaddr);
cle->GetCollectionProxy()->Clear();
pr->Destructor(eaddr, kTRUE);
} else {
pr->Destructor(eaddr, kTRUE);
}
}
}
if (etype == kObject + kOffsetL || etype == kAny + kOffsetL ||
etype == kTObject + kOffsetL || etype == kTString + kOffsetL ||
etype == kTNamed + kOffsetL || etype == kSTL + kOffsetL) {
Int_t len = ele->GetArrayLength();
Int_t size = cle->Size();
char* r = eaddr + (size * (len - 1));
for (Int_t j = len - 1; j >= 0; --j, r -= size) {
cle->Destructor(r, kTRUE);
}
}
}
if (!dtorOnly) {
delete[] p;
}
--fLiveCount;
}
void TStreamerInfo::Destructor(void* obj, Bool_t dtorOnly)
{
if (obj == 0) return;
char* p = (char*) obj;
if (!dtorOnly && fNVirtualInfoLoc) {
TStreamerInfo *allocator = *(TStreamerInfo**)(p + fVirtualInfoLoc[0]);
if (allocator != this) {
Int_t baseoffset = allocator->GetClass()->GetBaseClassOffset(GetClass());
p -= baseoffset;
allocator->DestructorImpl(p, kFALSE);
return;
}
}
DestructorImpl(p, dtorOnly);
}
void TStreamerInfo::DeleteArray(void* ary, Bool_t dtorOnly)
{
if (ary == 0) return;
Long_t* r = (Long_t*) ary;
Long_t arrayLen = r[-1];
Long_t size = r[-2];
char* memBegin = (char*) &r[-2];
char* p = ((char*) ary) + ((arrayLen - 1) * size);
for (Long_t cnt = 0; cnt < arrayLen; ++cnt, p -= size) {
Destructor(p, kTRUE);
}
if (!dtorOnly) {
delete[] memBegin;
}
}
void TStreamerInfo::PrintValue(const char *name, char *pointer, Int_t i, Int_t len, Int_t lenmax) const
{
char *ladd;
Int_t atype,aleng;
printf(" %-15s = ",name);
TStreamerElement * aElement = 0;
Int_t *count = 0;
if (len >= 0) {
ladd = pointer;
atype = i;
aleng = len;
} else {
if (i < 0) {
if (pointer==0) {
printf("NULL\n");
} else {
const static TClassRef stringClass("string");
if (fClass == stringClass) {
std::string *st = (std::string*)(pointer);
printf("%s\n",st->c_str());
} else if (fClass == TString::Class()) {
TString *st = (TString*)(pointer);
printf("%s\n",st->Data());
} else {
printf("(%s*)0x%lx\n",GetName(),(ULong_t)pointer);
}
}
return;
}
ladd = pointer + fCompFull[i]->fOffset;
atype = fCompFull[i]->fNewType;
aleng = fCompFull[i]->fLength;
aElement = (TStreamerElement*)fCompFull[i]->fElem;
count = (Int_t*)(pointer+fCompFull[i]->fMethod);
}
if (aleng > lenmax) aleng = lenmax;
PrintValueAux(ladd,atype,aElement,aleng,count);
printf("\n");
}
void TStreamerInfo::PrintValueClones(const char *name, TClonesArray *clones, Int_t i, Int_t eoffset, Int_t lenmax) const
{
if (!clones) {printf(" %-15s = \n",name); return;}
printf(" %-15s = ",name);
Int_t nc = clones->GetEntriesFast();
if (nc > lenmax) nc = lenmax;
Int_t offset = eoffset + fCompFull[i]->fOffset;
TStreamerElement *aElement = (TStreamerElement*)fCompFull[i]->fElem;
int aleng = fCompFull[i]->fLength;
if (aleng > lenmax) aleng = lenmax;
for (Int_t k=0;k < nc;k++) {
char *pointer = (char*)clones->UncheckedAt(k);
char *ladd = pointer+offset;
Int_t *count = (Int_t*)(pointer+fCompFull[i]->fMethod);
PrintValueAux(ladd,fCompFull[i]->fNewType,aElement, aleng, count);
if (k < nc-1) printf(", ");
}
printf("\n");
}
void TStreamerInfo::PrintValueSTL(const char *name, TVirtualCollectionProxy *cont, Int_t i, Int_t eoffset, Int_t lenmax) const
{
if (!cont) {printf(" %-15s = \n",name); return;}
printf(" %-15s = ",name);
Int_t nc = cont->Size();
if (nc > lenmax) nc = lenmax;
Int_t offset = eoffset + fCompFull[i]->fOffset;
TStreamerElement *aElement = (TStreamerElement*)fCompFull[i]->fElem;
int aleng = fCompFull[i]->fLength;
if (aleng > lenmax) aleng = lenmax;
for (Int_t k=0;k < nc;k++) {
char *pointer = (char*)cont->At(k);
char *ladd = pointer+offset;
Int_t *count = (Int_t*)(pointer+fCompFull[i]->fMethod);
PrintValueAux(ladd,fCompFull[i]->fNewType,aElement, aleng, count);
if (k < nc-1) printf(", ");
}
printf("\n");
}
void TStreamerInfo::Streamer(TBuffer &R__b)
{
UInt_t R__s, R__c;
if (R__b.IsReading()) {
Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
fOldVersion = R__v;
if (R__v > 1) {
R__b.ClassBegin(TStreamerInfo::Class(), R__v);
R__b.ClassMember("TNamed");
TNamed::Streamer(R__b);
fName = TClassEdit::GetLong64_Name( fName.Data() ).c_str();
R__b.ClassMember("fCheckSum","UInt_t");
R__b >> fCheckSum;
R__b.ClassMember("fClassVersion","Int_t");
R__b >> fClassVersion;
fOnFileClassVersion = fClassVersion;
R__b.ClassMember("fElements","TObjArray*");
R__b >> fElements;
R__b.ClassEnd(TStreamerInfo::Class());
R__b.SetBufferOffset(R__s+R__c+sizeof(UInt_t));
ResetBit(kIsCompiled);
ResetBit(kBuildOldUsed);
ResetBit(kBuildRunning);
if (R__b.GetParent() && R__b.GetVersionOwner() < 50000)
{
Int_t nobjects = fElements->GetEntriesFast();
TClass *basic = TStreamerBasicType::Class();
for (Int_t i = 0; i < nobjects; i++) {
TStreamerElement *el = (TStreamerElement*)fElements->UncheckedAt(i);
TStreamerElement *rel = 0;
if ( el->IsA() == basic ) {
switch (el->GetType()) {
default: break;
case TStreamerInfo::kObject:
rel = new TStreamerObject(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
break;
case TStreamerInfo::kAny:
rel = new TStreamerObjectAny(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
break;
case TStreamerInfo::kObjectp:
rel = new TStreamerObjectPointer(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
break;
case TStreamerInfo::kObjectP:
rel = new TStreamerObjectPointer(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
break;
case TStreamerInfo::kTString:
rel = new TStreamerObject(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
break;
}
if (rel) {
(*fElements)[i] = rel;
delete el;
}
}
}
}
return;
}
TNamed::Streamer(R__b);
fName = TClassEdit::GetLong64_Name( fName.Data() ).c_str();
R__b >> fCheckSum;
R__b >> fClassVersion;
fOnFileClassVersion = fClassVersion;
R__b >> fElements;
R__b.CheckByteCount(R__s, R__c, TStreamerInfo::IsA());
} else {
R__c = R__b.WriteVersion(TStreamerInfo::IsA(), kTRUE);
R__b.ClassBegin(TStreamerInfo::Class());
R__b.ClassMember("TNamed");
TNamed::Streamer(R__b);
R__b.ClassMember("fCheckSum","UInt_t");
R__b << fCheckSum;
R__b.ClassMember("fClassVersion","Int_t");
R__b << ((fClassVersion > 0) ? fClassVersion : -fClassVersion);
R__b.ClassMember("fElements","TObjArray*");
#if NOTYET
if (has_no_artificial_member) {
R__b << fElements;
} else
#endif
{
R__LOCKGUARD(gInterpreterMutex);
Int_t nobjects = fElements->GetEntriesFast();
TObjArray store( *fElements );
TStreamerElement *el;
for (Int_t i = 0; i < nobjects; i++) {
el = (TStreamerElement*)fElements->UncheckedAt(i);
if( el != 0 && (el->IsA() == TStreamerArtificial::Class() || el->TestBit(TStreamerElement::kRepeat))) {
fElements->RemoveAt( i );
} else if( el !=0 && (el->TestBit(TStreamerElement::kCache) && !el->TestBit(TStreamerElement::kWrite)) ) {
fElements->RemoveAt( i );
}
}
fElements->Compress();
R__b << fElements;
R__ASSERT(!fElements->IsOwner());
*fElements = store;
}
R__b.ClassEnd(TStreamerInfo::Class());
R__b.SetByteCount(R__c, kTRUE);
}
}
void TStreamerInfo::TagFile(TFile *file)
{
if (file) {
static std::atomic<Bool_t> onlyonce(kFALSE);
Bool_t expected = kFALSE;
if (onlyonce.compare_exchange_strong(expected,kTRUE)) {
Warning("TagFile","This function is deprecated, use TBuffer::TagStreamerInfo instead");
}
TArrayC *cindex = file->GetClassIndex();
Int_t nindex = cindex->GetSize();
if (fNumber < 0 || fNumber >= nindex) {
Error("TagFile","StreamerInfo: %s number: %d out of range[0,%d] in file: %s",
GetName(),fNumber,nindex,file->GetName());
return;
}
if (cindex->fArray[fNumber] == 0) {
cindex->fArray[0] = 1;
cindex->fArray[fNumber] = 1;
}
}
}
#ifdef DOLOOP
#undef DOLOOP
#endif
#define DOLOOP for (k = 0, pointer = arr[0]; k < narr; pointer = arr[++k])
namespace {
static void PrintCR(int j,Int_t aleng, UInt_t ltype)
{
if (j == aleng-1) printf("\n");
else {
printf(", ");
if (j%ltype == ltype-1) printf("\n ");
}
}
}
void TStreamerInfo::PrintValueAux(char *ladd, Int_t atype, TStreamerElement *aElement, Int_t aleng, Int_t *count)
{
int j;
switch (atype) {
case kBool: {Bool_t *val = (Bool_t* )ladd; printf("%d" ,*val); break;}
case kChar: {Char_t *val = (Char_t* )ladd; printf("%d" ,*val); break;}
case kShort: {Short_t *val = (Short_t* )ladd; printf("%d" ,*val); break;}
case kInt: {Int_t *val = (Int_t* )ladd; printf("%d" ,*val); break;}
case kLong: {Long_t *val = (Long_t* )ladd; printf("%ld",*val); break;}
case kLong64: {Long64_t *val = (Long64_t* )ladd; printf("%lld",*val); break;}
case kFloat: {Float_t *val = (Float_t* )ladd; printf("%f" ,*val); break;}
case kFloat16: {Float_t *val = (Float_t* )ladd; printf("%f" ,*val); break;}
case kDouble: {Double_t *val = (Double_t* )ladd; printf("%g" ,*val); break;}
case kDouble32: {Double_t *val = (Double_t* )ladd; printf("%g" ,*val); break;}
case kUChar: {UChar_t *val = (UChar_t* )ladd; printf("%u" ,*val); break;}
case kUShort: {UShort_t *val = (UShort_t* )ladd; printf("%u" ,*val); break;}
case kUInt: {UInt_t *val = (UInt_t* )ladd; printf("%u" ,*val); break;}
case kULong: {ULong_t *val = (ULong_t* )ladd; printf("%lu",*val); break;}
case kULong64: {ULong64_t *val = (ULong64_t*)ladd; printf("%llu",*val); break;}
case kBits: {UInt_t *val = (UInt_t* )ladd; printf("%d" ,*val); break;}
case kOffsetL + kBool: {Bool_t *val = (Bool_t* )ladd; for(j=0;j<aleng;j++) { printf("%c " ,val[j]); PrintCR(j,aleng,20); } break;}
case kOffsetL + kChar: {Char_t *val = (Char_t* )ladd; for(j=0;j<aleng;j++) { printf("%c " ,val[j]); PrintCR(j,aleng,20); } break;}
case kOffsetL + kShort: {Short_t *val = (Short_t* )ladd; for(j=0;j<aleng;j++) { printf("%d " ,val[j]); PrintCR(j,aleng,10); } break;}
case kOffsetL + kInt: {Int_t *val = (Int_t* )ladd; for(j=0;j<aleng;j++) { printf("%d " ,val[j]); PrintCR(j,aleng,10); } break;}
case kOffsetL + kLong: {Long_t *val = (Long_t* )ladd; for(j=0;j<aleng;j++) { printf("%ld ",val[j]); PrintCR(j,aleng, 5); } break;}
case kOffsetL + kLong64: {Long64_t *val = (Long64_t* )ladd; for(j=0;j<aleng;j++) { printf("%lld ",val[j]);PrintCR(j,aleng, 5); } break;}
case kOffsetL + kFloat: {Float_t *val = (Float_t* )ladd; for(j=0;j<aleng;j++) { printf("%f " ,val[j]); PrintCR(j,aleng, 5); } break;}
case kOffsetL + kFloat16: {Float_t *val = (Float_t* )ladd; for(j=0;j<aleng;j++) { printf("%f " ,val[j]); PrintCR(j,aleng, 5); } break;}
case kOffsetL + kDouble: {Double_t *val = (Double_t* )ladd; for(j=0;j<aleng;j++) { printf("%g " ,val[j]); PrintCR(j,aleng, 5); } break;}
case kOffsetL + kDouble32:{Double_t *val = (Double_t* )ladd; for(j=0;j<aleng;j++) { printf("%g " ,val[j]); PrintCR(j,aleng, 5); } break;}
case kOffsetL + kUChar: {UChar_t *val = (UChar_t* )ladd; for(j=0;j<aleng;j++) { printf("%u " ,val[j]); PrintCR(j,aleng,20); } break;}
case kOffsetL + kUShort: {UShort_t *val = (UShort_t* )ladd; for(j=0;j<aleng;j++) { printf("%u " ,val[j]); PrintCR(j,aleng,10); } break;}
case kOffsetL + kUInt: {UInt_t *val = (UInt_t* )ladd; for(j=0;j<aleng;j++) { printf("%u " ,val[j]); PrintCR(j,aleng, 5); } break;}
case kOffsetL + kULong: {ULong_t *val = (ULong_t* )ladd; for(j=0;j<aleng;j++) { printf("%lu ",val[j]); PrintCR(j,aleng, 5); } break;}
case kOffsetL + kULong64: {ULong64_t *val = (ULong64_t*)ladd; for(j=0;j<aleng;j++) { printf("%llu ",val[j]);PrintCR(j,aleng, 5); } break;}
case kOffsetL + kBits: {UInt_t *val = (UInt_t* )ladd; for(j=0;j<aleng;j++) { printf("%d " ,val[j]); PrintCR(j,aleng, 5); } break;}
case kOffsetP + kBool: {Bool_t **val = (Bool_t** )ladd; for(j=0;j<*count;j++) { printf("%d " ,(*val)[j]); PrintCR(j,aleng,20); } break;}
case kOffsetP + kChar: {Char_t **val = (Char_t** )ladd; for(j=0;j<*count;j++) { printf("%d " ,(*val)[j]); PrintCR(j,aleng,20); } break;}
case kOffsetP + kShort: {Short_t **val = (Short_t** )ladd; for(j=0;j<*count;j++) { printf("%d " ,(*val)[j]); PrintCR(j,aleng,10); } break;}
case kOffsetP + kInt: {Int_t **val = (Int_t** )ladd; for(j=0;j<*count;j++) { printf("%d " ,(*val)[j]); PrintCR(j,aleng,10); } break;}
case kOffsetP + kLong: {Long_t **val = (Long_t** )ladd; for(j=0;j<*count;j++) { printf("%ld ",(*val)[j]); PrintCR(j,aleng, 5); } break;}
case kOffsetP + kLong64: {Long64_t **val = (Long64_t**)ladd; for(j=0;j<*count;j++) { printf("%lld ",(*val)[j]); PrintCR(j,aleng, 5); } break;}
case kOffsetP + kFloat: {Float_t **val = (Float_t** )ladd; for(j=0;j<*count;j++) { printf("%f " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
case kOffsetP + kFloat16: {Float_t **val = (Float_t** )ladd; for(j=0;j<*count;j++) { printf("%f " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
case kOffsetP + kDouble: {Double_t **val = (Double_t**)ladd; for(j=0;j<*count;j++) { printf("%g " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
case kOffsetP + kDouble32:{Double_t **val = (Double_t**)ladd; for(j=0;j<*count;j++) { printf("%g " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
case kOffsetP + kUChar: {UChar_t **val = (UChar_t** )ladd; for(j=0;j<*count;j++) { printf("%u " ,(*val)[j]); PrintCR(j,aleng,20); } break;}
case kOffsetP + kUShort: {UShort_t **val = (UShort_t**)ladd; for(j=0;j<*count;j++) { printf("%u " ,(*val)[j]); PrintCR(j,aleng,10); } break;}
case kOffsetP + kUInt: {UInt_t **val = (UInt_t** )ladd; for(j=0;j<*count;j++) { printf("%u " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
case kOffsetP + kULong: {ULong_t **val = (ULong_t** )ladd; for(j=0;j<*count;j++) { printf("%lu ",(*val)[j]); PrintCR(j,aleng, 5); } break;}
case kOffsetP + kULong64: {ULong64_t**val = (ULong64_t**)ladd; for(j=0;j<*count;j++){ printf("%llu ",(*val)[j]); PrintCR(j,aleng, 5); } break;}
case kCounter: {Int_t *val = (Int_t*)ladd; printf("%d",*val); break;}
case kCharStar:{
char **val = (char**)ladd;
if (*val) printf("%s",*val);
break;
}
case kObjectp: {
TObject **obj = (TObject**)(ladd);
TStreamerObjectPointer *el = (TStreamerObjectPointer*)aElement;
printf("(%s*)%lx",el ? el->GetClass()->GetName() : "unknown_type",(Long_t)(*obj));
break;
}
case kObjectP: {
TObject **obj = (TObject**)(ladd);
TStreamerObjectPointer *el = (TStreamerObjectPointer*)aElement;
printf("(%s*)%lx",el ? el->GetClass()->GetName() : "unknown_type",(Long_t)(*obj));
break;
}
case kObject: {
TObject *obj = (TObject*)(ladd);
printf("%s",obj->GetName());
break;
}
case kTString: {
TString *st = (TString*)(ladd);
printf("%s",st->Data());
break;
}
case kTObject: {
TObject *obj = (TObject*)(ladd);
printf("%s",obj->GetName());
break;
}
case kTNamed: {
TNamed *named = (TNamed*) (ladd);
printf("%s/%s",named->GetName(),named->GetTitle());
break;
}
case kAnyp: {
TObject **obj = (TObject**)(ladd);
TStreamerObjectAnyPointer *el = (TStreamerObjectAnyPointer*)aElement;
printf("(%s*)0x%lx",el ? el->GetClass()->GetName() : "unknown_type",(Long_t)(*obj));
break;
}
case kAnyP: {
TObject **obj = (TObject**)(ladd);
TStreamerObjectAnyPointer *el = (TStreamerObjectAnyPointer*)aElement;
printf("(%s*)0x%lx",el ? el->GetClass()->GetName() : "unknown_type",(Long_t)(*obj));
break;
}
case kOffsetL + kObjectp:
case kOffsetL + kObjectP:
case kAny: {
printf("printing kAny case (%d)",atype);
break;
}
case kBase: {
printf("printing kBase case (%d)",atype);
break;
}
case kOffsetL + kObject:
case kOffsetL + kTString:
case kOffsetL + kTObject:
case kOffsetL + kTNamed:
case kStreamer: {
printf("printing kStreamer case (%d)",atype);
break;
}
case kStreamLoop: {
printf("printing kStreamLoop case (%d)",atype);
break;
}
case kSTL: {
if (aElement) {
static TClassRef stringClass("string");
if (ladd && aElement->GetClass() == stringClass) {
std::string *st = (std::string*)(ladd);
printf("%s",st->c_str());
} else {
printf("(%s*)0x%lx",aElement->GetClass()->GetName(),(Long_t)(ladd));
}
} else {
printf("(unknown_type*)0x%lx",(Long_t)(ladd));
}
break;
}
}
}
void TStreamerInfo::Update(const TClass *oldcl, TClass *newcl)
{
TStreamerElement *element;
TIter nextElement(GetElements());
while ((element = (TStreamerElement*)nextElement())) {
element->Update(oldcl,newcl);
}
for (Int_t i=0;i < fNslots;i++) {
fComp[i].Update(oldcl,newcl);
}
}
void TStreamerInfo::TCompInfo::Update(const TClass *oldcl, TClass *newcl)
{
if (fType != -1) {
if (fClass == oldcl)
fClass = newcl;
else if (fClass == 0)
fClass = TClass::GetClass(fClassName);
}
}
TVirtualCollectionProxy*
TStreamerInfo::GenEmulatedProxy(const char* class_name, Bool_t silent)
{
return TCollectionProxyFactory::GenEmulatedProxy(class_name, silent);
}
TClassStreamer*
TStreamerInfo::GenEmulatedClassStreamer(const char* class_name, Bool_t silent)
{
return TCollectionProxyFactory::GenEmulatedClassStreamer(class_name, silent);
}
TVirtualCollectionProxy*
TStreamerInfo::GenExplicitProxy( const ::ROOT::TCollectionProxyInfo &info, TClass *cl )
{
return TCollectionProxyFactory::GenExplicitProxy(info, cl);
}
TClassStreamer*
TStreamerInfo::GenExplicitClassStreamer( const ::ROOT::TCollectionProxyInfo &info, TClass *cl )
{
return TCollectionProxyFactory::GenExplicitClassStreamer(info, cl);
}