Logo ROOT   6.10/09
Reference Guide
TStreamerInfo.cxx
Go to the documentation of this file.
1 // @(#)root/io:$Id$
2 // Author: Rene Brun 12/10/2000
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 /**
13 \class TStreamerInfo TStreamerInfo.cxx
14 \ingroup IO
15 
16 Describes a persistent version of a class.
17 
18 A ROOT file contains the list of TStreamerInfo objects for all the
19 class versions written to this file.
20 When reading a file, all the TStreamerInfo objects are read back in
21 memory and registered to the TClass list of TStreamerInfo.
22 One can see the list and contents of the TStreamerInfo on a file
23 with, e.g.,
24 ~~~{.cpp}
25  TFile f("myfile.root");
26  f.ShowStreamerInfo();
27 ~~~
28 A TStreamerInfo is a list of TStreamerElement objects (one per data
29 member or base class).
30 When streaming an object, the system (TClass) loops on all the
31 TStreamerElement objects and calls the appropriate function for each
32 element type.
33 */
34 
35 #include "TStreamerInfo.h"
36 #include "TFile.h"
37 #include "TROOT.h"
38 #include "TClonesArray.h"
39 #include "TStreamerElement.h"
40 #include "TClass.h"
41 #include "TClassEdit.h"
42 #include "TDataMember.h"
43 #include "TMethodCall.h"
44 #include "TDataType.h"
45 #include "TRealData.h"
46 #include "TBaseClass.h"
47 #include "TBuffer.h"
48 #include "TArrayC.h"
49 #include "TArrayI.h"
50 #include "TArrayF.h"
51 #include "TArrayD.h"
52 #include "TArrayS.h"
53 #include "TArrayL.h"
54 #include "TError.h"
55 #include "TRef.h"
56 #include "TProcessID.h"
57 #include "TSystem.h"
58 
59 #include "TStreamer.h"
60 #include "TContainerConverters.h"
63 #include "TInterpreter.h"
64 
65 #include "TMemberInspector.h"
66 
67 #include "TMakeProject.h"
68 
69 #include "TSchemaRuleSet.h"
70 #include "TSchemaRule.h"
71 
72 #include "TVirtualMutex.h"
73 
74 #include "TStreamerInfoActions.h"
75 
76 #include <memory>
77 #include <array>
78 
79 std::atomic<Int_t> TStreamerInfo::fgCount{0};
80 
81 const Int_t kMaxLen = 1024;
82 
84 
85 static void R__TObjArray_InsertAt(TObjArray *arr, TObject *obj, Int_t at)
86 {
87  // Slide by one.
88  Int_t last = arr->GetLast();
89  arr->AddAtAndExpand(arr->At(last),last+1);
90  for(Int_t ind = last-1; ind >= at; --ind) {
91  arr->AddAt( arr->At(ind), ind+1);
92  };
93  arr->AddAt( obj, at);
94 }
95 
96 static void R__TObjArray_InsertAt(TObjArray *arr, std::vector<TStreamerArtificial*> &objs, Int_t at)
97 {
98  // Slide by enough.
99  Int_t offset = objs.size();
100  Int_t last = arr->GetLast();
101  arr->AddAtAndExpand(arr->At(last),last+offset);
102  for(Int_t ind = last-1; ind >= at; --ind) {
103  arr->AddAt( arr->At(ind), ind+offset);
104  };
105  for(size_t ins = 0; ins < objs.size(); ++ins) {
106  arr->AddAt(objs[ins], at+ins);
107  }
108 }
109 
110 static void R__TObjArray_InsertAfter(TObjArray *arr, TObject *newobj, TObject *oldobj)
111 {
112  // Slide by one.
113  Int_t last = arr->GetLast();
114  Int_t at = 0;
115  while (at<last && arr->At(at) != oldobj) {
116  ++at;
117  }
118  ++at; // we found the object, insert after it
119  R__TObjArray_InsertAt(arr, newobj, at);
120 }
121 
122 static void R__TObjArray_InsertBefore(TObjArray *arr, TObject *newobj, TObject *oldobj)
123 {
124  // Slide by one.
125  Int_t last = arr->GetLast();
126  Int_t at = 0;
127  while (at<last && arr->At(at) != oldobj) {
128  ++at;
129  }
130  R__TObjArray_InsertAt(arr, newobj, at);
131 }
132 
133 enum class EUniquePtrOffset : char
134  {
135  kNA = 0,
136  kZero = 1,
137  kNonZero = 2
138  };
139 
140 ////////////////////////////////////////////////////////////////////////////////
141 /// Default ctor.
142 
144 {
145  fNumber = fgCount;
146  fClass = 0;
147  fElements = 0;
148  fComp = 0;
149  fCompFull = 0;
150  fCompOpt = 0;
151  fCheckSum = 0;
152  fNdata = 0;
153  fNfulldata= 0;
154  fNslots = 0;
155  fSize = 0;
156  fClassVersion = 0;
157  fOnFileClassVersion = 0;
158  fOldVersion = Class()->GetClassVersion();
159  fNVirtualInfoLoc = 0;
160  fVirtualInfoLoc = 0;
161  fLiveCount = 0;
162 
163  fReadObjectWise = 0;
164  fReadMemberWise = 0;
165  fReadMemberWiseVecPtr = 0;
166  fWriteObjectWise = 0;
167  fWriteMemberWise = 0;
168  fWriteMemberWiseVecPtr = 0;
169 }
170 
171 ////////////////////////////////////////////////////////////////////////////////
172 /// Create a TStreamerInfo object.
173 
176 {
177  fgCount++;
178  fNumber = fgCount;
179  fClass = cl;
180  fElements = new TObjArray();
181  fComp = 0;
182  fCompFull = 0;
183  fCompOpt = 0;
184  fCheckSum = 0;
185  fNdata = 0;
186  fNfulldata= 0;
187  fNslots = 0;
188  fSize = 0;
191  fOldVersion = Class()->GetClassVersion();
192  fNVirtualInfoLoc = 0;
193  fVirtualInfoLoc = 0;
194  fLiveCount = 0;
195 
196  fReadObjectWise = 0;
197  fReadMemberWise = 0;
199  fWriteObjectWise = 0;
200  fWriteMemberWise = 0;
202 }
203 
204 ////////////////////////////////////////////////////////////////////////////////
205 /// TStreamerInfo dtor.
206 
208 {
209  delete [] fComp; fComp = 0;
210  delete [] fCompFull; fCompFull = 0;
211  delete [] fCompOpt; fCompOpt = 0;
212  delete [] fVirtualInfoLoc; fVirtualInfoLoc =0;
213 
214  delete fReadObjectWise;
215  delete fReadMemberWise;
216  delete fReadMemberWiseVecPtr;
217  delete fWriteObjectWise;
218  delete fWriteMemberWise;
219  delete fWriteMemberWiseVecPtr;
220 
221  if (!fElements) return;
222  fElements->Delete();
223  delete fElements; fElements=0;
224 }
225 
226 ////////////////////////////////////////////////////////////////////////////////
227 /// Makes sure kBuildOldUsed set once Build or BuildOld finishes.
228 /// Makes sure kBuildRunning reset once Build finishes.
229 
230 namespace {
231  struct TPreventRecursiveBuildGuard {
232  TPreventRecursiveBuildGuard(TStreamerInfo* info): fInfo(info) {
233  fInfo->SetBit(TStreamerInfo::kBuildRunning);
234  fInfo->SetBit(TStreamerInfo::kBuildOldUsed);
235  }
236  ~TPreventRecursiveBuildGuard() {
237  fInfo->ResetBit(TStreamerInfo::kBuildOldUsed);
238  fInfo->ResetBit(TStreamerInfo::kBuildRunning);
239  }
240  TStreamerInfo* fInfo;
241  };
242 
243 }
244 
245 ////////////////////////////////////////////////////////////////////////////////
246 /// Build the I/O data structure for the current class version.
247 ///
248 /// A list of TStreamerElement derived classes is built by scanning
249 /// one by one the list of data members of the analyzed class.
251 {
252  // Did another thread already do the work?
253  if (fIsCompiled) return;
254 
256 
257  // Did another thread already do the work while we were waiting ..
258  if (fIsCompiled) return;
259 
260  // Has Build already been run?
261  if (fIsBuilt) return;
262 
263  // Are we recursing on ourself?
265 
266  // This is used to avoid unwanted recursive call to Build or BuildOld.
267  TPreventRecursiveBuildGuard buildGuard(this);
268 
269  if (fClass->GetCollectionProxy()) {
271  TString title;
272  if (proxy->GetValueClass()) {
273  title.Form("<%s%s> Used to call the proper TStreamerInfo case",proxy->GetValueClass()->GetName(),proxy->HasPointers() ? "*" : "");
274  } else {
275  title .Form("<%s%s> Used to call the proper TStreamerInfo case",TDataType::GetTypeName(proxy->GetType()),proxy->HasPointers() ? "*" : "");
276  }
277  TStreamerElement* element = new TStreamerSTL("This", title.Data(), 0, fClass->GetName(), *proxy, 0);
278  fElements->Add(element);
279  Compile();
281  fIsBuilt = kTRUE;
282  return;
283  }
284 
285  TStreamerElement::Class()->IgnoreTObjectStreamer();
286 
288 
290 
291  Bool_t needAllocClass = kFALSE;
292  Bool_t wasCompiled = fComp != 0;
293  ROOT::TSchemaRuleSet::TMatches rules;
294  if (fClass->GetSchemaRules()) {
296  }
297 
298  //
299  // Iterate over base classes.
300  //
301 
302  bool isCollection = fClass->GetCollectionProxy();
303  bool isString = !strcmp(fClass->GetName(), "string");
304 
305  TBaseClass* base = 0;
306  TIter nextb(fClass->GetListOfBases());
307  while ((base = (TBaseClass*)nextb())) {
308  TStreamerElement* element = 0;
309  Int_t offset = base->GetDelta();
310  if (offset == kMissing) {
311  continue;
312  }
313  if (offset == kNeedObjectForVirtualBaseClass) {
314  Error("Build()", "Cannot stream virtual base %s of class %s",
315  base->GetName(), fClass->GetName());
316  continue;
317  }
318  const char* bname = base->GetName();
319  const char* btitle = base->GetTitle();
320  // this case appears with STL collections as base class.
321  if (!strcmp(bname, "string")) {
322  element = new TStreamerSTLstring(bname, btitle, offset, bname, kFALSE);
323  } else if (base->IsSTLContainer()) {
324  TVirtualCollectionProxy *proxy = base->GetClassPointer()->GetCollectionProxy();
325  if (proxy) element = new TStreamerSTL(bname, btitle, offset, bname, *proxy, kFALSE);
326  else element = new TStreamerSTL(bname, btitle, offset, bname, 0, kFALSE);
327  if (fClass->IsLoaded() && ((TStreamerSTL*)element)->GetSTLtype() != ROOT::kSTLvector) {
328  if (!element->GetClassPointer()->IsLoaded()) {
329  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);
330  delete element;
331  continue;
332  }
333  }
334  } else {
335  element = new TStreamerBase(bname, btitle, offset);
336  TClass* clm = element->GetClassPointer();
337  if (!clm) {
338  // We have no information about the class yet, except that since it
339  // is a base class, we know it is a class. So let's create it (in v5
340  // it would have been created as a side effect of the dictionary of
341  // for the derived class having a forward declaration of the base class).
342  clm = new TClass(bname,1,TClass::kForwardDeclared, true /*silent*/);
343  Warning("Build", "%s: base class %s has no streamer or dictionary it will not be saved", GetName(), clm->GetName());
344  element->Init(0);
345  } else {
346  // Now part of the TStreamerBase constructor.
347  // clm->GetStreamerInfo();
348  if ((clm == TObject::Class()) && fClass->CanIgnoreTObjectStreamer()) {
349  // -- An ignored TObject base class.
350  // Note: The TClass kIgnoreTObjectStreamer == BIT(15), but
351  // the TStreamerInfo kIgnoreTobjectStreamer == BIT(13) which
352  // is confusing.
354  // Flag the element to be ignored by setting its type to -1.
355  // This flag will be used later by Compile() to prevent this
356  // element from being inserted into the compiled info.
357  element->SetType(-1);
358  }
359  if (!clm->IsLoaded() && !(isCollection || isString)) {
360  // Don't complain about the base classes of collections nor of
361  // std::string.
362  Warning("Build", "%s: base class %s has no streamer or dictionary it will not be saved", GetName(), clm->GetName());
363  }
364  }
365  }
366  if (element) {
367  fElements->Add(element);
368  }
369  } // end of base class loop
370 
371  //
372  // Iterate over data members.
373  //
374 
375  Int_t dsize;
376  TDataMember* dm = 0;
377  std::string typeNameBuf;
378  std::string trueTypeNameBuf;
380  while ((dm = (TDataMember*) nextd())) {
381  if (fClass->GetClassVersion() == 0) {
382  continue;
383  }
384  if (!dm->IsPersistent()) {
385  continue;
386  }
387  TMemberStreamer* streamer = 0;
388  Int_t offset = GetDataMemberOffset(dm, streamer);
389  if (offset == kMissing) {
390  continue;
391  }
392  TStreamerElement* element = 0;
393  dsize = 0;
394 
395  // Save some useful variables
396  const char* dmName = dm->GetName();
397  const char* dmTitle = dm->GetTitle();
398  const char* dmType = dm->GetTypeName();
399  const char* dmFull = dm->GetTrueTypeName(); // Used to be GetFullTypeName ...
400  Bool_t dmIsPtr = dm->IsaPointer();
401  TDataType* dt(nullptr);
402  Int_t ndim = dm->GetArrayDim();
403  std::array<Int_t, 5> maxIndices; // 5 is the maximum supported in TStreamerElement::SetMaxIndex
404  Bool_t isStdArray(kFALSE);
405 
406  // Let's treat the unique_ptr case
407  bool nameChanged;
408  trueTypeNameBuf = typeNameBuf = TClassEdit::GetNameForIO(dmFull, TClassEdit::EModType::kNone, &nameChanged);
409  if (nameChanged) {
410  if (TClassEdit::IsUniquePtr(dmFull)) {
411  dmIsPtr = true;
412  }
413  while(typeNameBuf.back() == '*') typeNameBuf.pop_back();
414  dmFull = trueTypeNameBuf.c_str();
415  dmType = typeNameBuf.c_str();
416  }
417  if ((isStdArray = TClassEdit::IsStdArray(dmType))){ // We tackle the std array case
418  TClassEdit::GetStdArrayProperties(dmType,
419  typeNameBuf,
420  maxIndices,
421  ndim);
422  trueTypeNameBuf = typeNameBuf;
423  while(typeNameBuf.back() == '*') typeNameBuf.pop_back();
424  dmFull = dmType = typeNameBuf.c_str();
425  dt = gROOT->GetType(dmType);
426  }
427 
428  TDataMember* dmCounter = 0;
429  if (dmIsPtr) {
430  //
431  // look for a pointer data member with a counter
432  // in the comment string, like so:
433  //
434  // int n;
435  // double* MyArray; //[n]
436  //
437  const char* lbracket = TVirtualStreamerInfo::GetElementCounterStart(dmTitle);
438  const char* rbracket = ::strchr(dmTitle, ']');
439  if (lbracket && rbracket) {
440  const char* counterName = dm->GetArrayIndex();
441  TRealData* rdCounter = (TRealData*) fClass->GetListOfRealData()->FindObject(counterName);
442  if (!rdCounter || rdCounter->TestBit(TRealData::kTransient)) {
443  Error("Build", "%s, discarding: %s %s, illegal %s\n", GetName(), dmFull, dmName, dmTitle);
444  continue;
445  }
446  dmCounter = rdCounter->GetDataMember();
447  TDataType* dtCounter = dmCounter->GetDataType();
448  Bool_t isInteger = dtCounter && ((dtCounter->GetType() == 3) || (dtCounter->GetType() == 13));
449  if (!dtCounter || !isInteger) {
450  Error("Build", "%s, discarding: %s %s, illegal [%s] (must be Int_t)\n", GetName(), dmFull, dmName, counterName);
451  continue;
452  }
453  TStreamerBasicType* bt = TStreamerInfo::GetElementCounter(counterName, dmCounter->GetClass());
454  if (!bt) {
455  if (dmCounter->GetClass()->Property() & kIsAbstract) {
456  continue;
457  }
458  Error("Build", "%s, discarding: %s %s, illegal [%s] must be placed before \n", GetName(), dmFull, dmName, counterName);
459  continue;
460  }
461  }
462  }
463  if (!dt && !isStdArray) dt = dm->GetDataType();
464  if (dt) {
465  // found a basic type
466  Int_t dtype = dt->GetType();
467  dsize = dt->Size();
468  if (!dmCounter && (strstr(dmFull, "char*") || strstr(dmFull, "Char_t*"))) {
469  dtype = kCharStar;
470  dsize = sizeof(char*);
471  }
472  if (dtype == kOther_t || dtype == kNoType_t) {
473  Error("Build", "%s, unknown type: %s %s", GetName(), dmFull, dmName);
474  continue;
475  } else if (dmIsPtr && (dtype != kCharStar)) {
476  if (dmCounter) {
477  // data member is pointer to an array of basic types
478  element = new TStreamerBasicPointer(dmName, dmTitle, offset, dtype, dm->GetArrayIndex(), dmCounter->GetClass()->GetName(), dmCounter->GetClass()->GetClassVersion(), dmFull);
479  } else {
480  if ((fName == "TString") || (fName == "TClass")) {
481  continue;
482  }
483  Error("Build", "%s, discarding: %s %s, no [dimension]\n", GetName(), dmFull, dmName);
484  continue;
485  }
486  } else {
487  // data member is a basic type
488  if ((fClass == TObject::Class()) && !strcmp(dmName, "fBits")) {
489  //printf("found fBits, changing dtype from %d to 15\n", dtype);
490  dtype = kBits;
491  }
492  // Here we treat data members such as int, float, double[4]
493  element = new TStreamerBasicType(dmName, dmTitle, offset, dtype, dmFull);
494  }
495  } else {
496  // try STL container or string
497  static const char* full_string_name = "basic_string<char,char_traits<char>,allocator<char> >";
498  if (!strcmp(dmType, "string") || !strcmp(dmType, "std::string") || !strcmp(dmType, full_string_name)) {
499  element = new TStreamerSTLstring(dmName, dmTitle, offset, dmFull, dmIsPtr);
500  } else if (dm->IsSTLContainer()) {
501  TVirtualCollectionProxy *proxy = TClass::GetClass(dmType /* the underlying type */)->GetCollectionProxy();
502  if (proxy) element = new TStreamerSTL(dmName, dmTitle, offset, dmFull, *proxy, dmIsPtr);
503  else element = new TStreamerSTL(dmName, dmTitle, offset, dmFull, dmFull, dmIsPtr);
504  if (((TStreamerSTL*)element)->GetSTLtype() != ROOT::kSTLvector) {
505  auto printErrorMsg = [&](const char* category)
506  {
507  Error("Build","The class \"%s\" is %s and for its data member \"%s\" we do not have a dictionary for the collection \"%s\". Because of this, we will not be able to read or write this data member.",GetName(), category, dmName, dmType);
508  };
509  if (fClass->IsLoaded()) {
510  if (!element->GetClassPointer()->IsLoaded()) {
511  printErrorMsg("compiled");
512  delete element;
513  continue;
514  }
515  } else if (fClass->GetState() == TClass::kInterpreted) {
517  printErrorMsg("interpreted");
518  delete element;
519  continue;
520  }
521  }
522  }
523  } else {
524  TClass* clm = TClass::GetClass(dmType);
525  if (!clm) {
526  Error("Build", "%s, unknown type: %s %s\n", GetName(), dmFull, dmName);
527  continue;
528  }
529  if (isStdArray) {
530  // We do not want to rebuild the streamerinfo of an std::array<T,N> asking the dm->GetUnitSize(), but rather of T only.
531 
532  dsize = clm->Size();
533  }
534  if (dmIsPtr) {
535  // a pointer to a class
536  if (dmCounter) {
537  element = new TStreamerLoop(dmName, dmTitle, offset, dm->GetArrayIndex(), dmCounter->GetClass()->GetName(), dmCounter->GetClass()->GetClassVersion(), dmFull);
538  } else {
539  if (clm->IsTObject()) {
540  element = new TStreamerObjectPointer(dmName, dmTitle, offset, dmFull);
541  } else {
542  element = new TStreamerObjectAnyPointer(dmName, dmTitle, offset, dmFull);
543  if (!streamer && !clm->GetStreamer() && !clm->IsLoaded()) {
544  Error("Build", "%s: %s has no streamer or dictionary, data member %s will not be saved", GetName(), dmFull, dmName);
545  }
546  }
547  }
548  } else if (clm->IsTObject()) {
549  element = new TStreamerObject(dmName, dmTitle, offset, dmFull);
550  } else if ((clm == TString::Class()) && !dmIsPtr) {
551  element = new TStreamerString(dmName, dmTitle, offset);
552  } else {
553  element = new TStreamerObjectAny(dmName, dmTitle, offset, dmFull);
554  if (!streamer && !clm->GetStreamer() && !clm->IsLoaded()) {
555  Warning("Build", "%s: %s has no streamer or dictionary, data member \"%s\" will not be saved", GetName(), dmFull, dmName);
556  }
557  }
558  }
559  }
560  if (!element) {
561  // If we didn't make an element, there is nothing to do.
562  continue;
563  }
564  if (!dsize) {
565  dsize = dm->GetUnitSize();
566  }
567  for (Int_t i = 0; i < ndim; ++i) {
568  auto maxIndex = 0;
569  if (isStdArray) maxIndex = maxIndices[i];
570  else maxIndex = dm->GetMaxIndex(i);
571  element->SetMaxIndex(i, maxIndex);
572  }
573  element->SetArrayDim(ndim);
574  // If the datamember was a int[4] this is 4, if double[3][2] 3*2=6
575  Int_t narr = element->GetArrayLength();
576  if (!narr) {
577  narr = 1;
578  }
579  element->SetSize(dsize*narr);
580  element->SetStreamer(streamer);
581  if (!streamer) {
582  Int_t k = element->GetType();
583  if (k == kStreamer) {
584  //if ((k == kSTL) || (k == kSTL + kOffsetL) || (k == kStreamer) || (k == kStreamLoop))
585  element->SetType(-1);
586  }
587  }
588 
589  if ( !wasCompiled && (rules && rules.HasRuleWithSource( element->GetName(), kTRUE )) ) {
590  needAllocClass = kTRUE;
591 
592  // If this is optimized to re-use TStreamerElement(s) in case of variable renaming,
593  // then we must revisit the code in TBranchElement::InitInfo that recalculate the
594  // fID (i.e. the index of the TStreamerElement to be used for streaming).
595 
596  TStreamerElement *cached = element;
597  // Now that we are caching the unconverted element, we do not assign it to the real type even if we could have!
598  if (element->GetNewType()>0 /* intentionally not including base class for now */
599  && rules && !rules.HasRuleWithTarget( element->GetName(), kTRUE ) )
600  {
601  TStreamerElement *copy = (TStreamerElement*)element->Clone();
602  fElements->Add(copy);
604  cached = copy;
605 
606  // Warning("BuildOld","%s::%s is not set from the version %d of %s (You must add a rule for it)\n",GetName(), element->GetName(), GetClassVersion(), GetName() );
607  } else {
608  // If the element is just cached and not repeat, we need to inject an element
609  // to insure the writing.
610  TStreamerElement *writecopy = (TStreamerElement*)element->Clone();
611  fElements->Add(element);
612  writecopy->SetBit(TStreamerElement::kWrite);
613  writecopy->SetNewType( writecopy->GetType() );
614  // Put the write element after the read element (that does caching).
615  element = writecopy;
616  }
618  cached->SetNewType( cached->GetType() );
619  }
620 
621  fElements->Add(element);
622  } // end of member loop
623 
624  // Now add artificial TStreamerElement (i.e. rules that creates new members or set transient members).
626 
627  if (needAllocClass) {
629  if (!infoalloc) {
630  Error("Build","Could you create a TStreamerInfo for %s\n",TString::Format("%s@@%d",GetName(),GetClassVersion()).Data());
631  } else {
632  // Tell clone we should rerun BuildOld
633  infoalloc->SetBit(kBuildOldUsed,false);
634  infoalloc->BuildCheck();
635  infoalloc->BuildOld();
636  TClass *allocClass = infoalloc->GetClass();
637 
638  {
639  TIter next(fElements);
640  TStreamerElement* element;
641  while ((element = (TStreamerElement*) next())) {
642  if (element->TestBit(TStreamerElement::kRepeat) && element->IsaPointer()) {
643  TStreamerElement *other = (TStreamerElement*) infoalloc->GetElements()->FindObject(element->GetName());
644  if (other) {
646  }
647  }
648  }
649  infoalloc->GetElements()->Compress();
650  }
651  {
652  TIter next(fElements);
653  TStreamerElement* element;
654  while ((element = (TStreamerElement*) next())) {
655  if (element->TestBit(TStreamerElement::kCache)) {
656  element->SetOffset(infoalloc->GetOffset(element->GetName()));
657  }
658  }
659  }
660 
661  TStreamerElement *el = new TStreamerArtificial("@@alloc","", 0, TStreamerInfo::kCacheNew, allocClass->GetName());
663 
664  el = new TStreamerArtificial("@@dealloc","", 0, TStreamerInfo::kCacheDelete, allocClass->GetName());
665  fElements->Add( el );
666  }
667  }
668 
669  //
670  // Make a more compact version.
671  //
672  Compile();
673  fIsBuilt = kTRUE;
674 }
675 
676 ////////////////////////////////////////////////////////////////////////////////
677 /// Check if built and consistent with the class dictionary.
678 /// This method is called by TFile::ReadStreamerInfo.
679 
681 {
683 
685  if (!fClass) {
686  // fClassVersion should have been a Version_t and/or Version_t
687  // should have been an Int_t. Changing the on-file format
688  // of the StreamerInfo is 'hard' (for forward compatibility), so
689  // leave it as is for now.
692 
693  // Case of a custom collection (the user provided a CollectionProxy
694  // for a class that is not an STL collection).
695  if (GetElements()->GetEntries() == 1) {
696  TObject *element = GetElements()->UncheckedAt(0);
697  Bool_t isstl = element && strcmp("This",element->GetName())==0;
698  if (isstl) {
699  if (element->GetTitle()[0] == '<') {
700  // We know the content.
701  TString content = element->GetTitle();
702  Int_t level = 1;
703  for(Int_t c = 1; c < content.Length(); ++c) {
704  if (content[c] == '<') ++level;
705  else if (content[c] == '>') --level;
706  if (level == 0) {
707  content.Remove(c+1);
708  break;
709  }
710  }
711  content.Prepend("vector");
712  TClass *clequiv = TClass::GetClass(content);
713  TVirtualCollectionProxy *proxy = clequiv->GetCollectionProxy();
714  if (gDebug > 1)
715  Info("BuildCheck",
716  "Update the collection proxy of the class \"%s\" \n"
717  "\tto be similar to \"%s\".",
718  GetName(),content.Data());
719  fClass->CopyCollectionProxy( *proxy );
720  } else {
721  Warning("BuildCheck", "\n\
722  The class %s had a collection proxy when written but it is not an STL\n \
723  collection and we did not record the type of the content of the collection.\n \
724  We will claim the content is a bool (i.e. no data will be read).",
725  GetName());
726  }
727  }
728  }
729 
730  } else {
731  if (fClass->GetCollectionType() > ROOT::kNotSTL) {
732  if (TClassEdit::IsSTLCont(fClass->GetName())) {
733  // We have a collection that is indeed an STL collection,
734  // we know we don't need its streamerInfo.
736  return;
737  }
738  }
739  const TObjArray *array = fClass->GetStreamerInfos();
740  TStreamerInfo* info = 0;
741 
742  if (fClass->TestBit(TClass::kIsEmulation) && array->GetEntries()==0) {
743  // We have an emulated class that has no TStreamerInfo, this
744  // means it was created to insert a (default) rule. Consequently
745  // the error message about the missing dictionary was not printed.
746  // For consistency, let's print it now!
747 
748  ::Warning("TClass::TClass", "no dictionary for class %s is available", GetName());
749  }
750 
751  // Case of a custom collection (the user provided a CollectionProxy
752  // for a class that is not an STL collection).
753  if (GetElements()->GetEntries() == 1) {
754  TObject *element = GetElements()->UncheckedAt(0);
755  Bool_t isstl = element && strcmp("This",element->GetName())==0;
756  if (isstl && !fClass->GetCollectionProxy()) {
757  if (element->GetTitle()[0] == '<') {
758  // We know the content.
759  TString content = element->GetTitle();
760  Int_t level = 1;
761  for(Int_t c = 1; c < content.Length(); ++c) {
762  if (content[c] == '<') ++level;
763  else if (content[c] == '>') --level;
764  if (level == 0) {
765  content.Remove(c+1);
766  break;
767  }
768  }
769  content.Prepend("vector");
770  TClass *clequiv = TClass::GetClass(content);
771  TVirtualCollectionProxy *proxy = clequiv->GetCollectionProxy();
772  if (gDebug > 1)
773  Info("BuildCheck",
774  "Update the collection proxy of the class \"%s\" \n"
775  "\tto be similar to \"%s\".",
776  GetName(),content.Data());
777  fClass->CopyCollectionProxy( *proxy );
778  } else {
779  Warning("BuildCheck", "\n\
780  The class %s had a collection proxy when written but it is not an STL\n \
781  collection and we did not record the type of the content of the collection.\n \
782  We will claim the content is a bool (i.e. no data will be read).",
783  GetName());
784  }
786  return;
787  }
788  }
789 
790  // If the user has not specified a class version (this _used to_
791  // always be the case when the class is Foreign) or if the user
792  // has specified a version to be explicitly 1. [We can not
793  // distinguish the two cases using the information in the "on
794  // file" StreamerInfo.]
795 
796  Bool_t searchOnChecksum = kFALSE;
797  if (fClass->IsLoaded() && fClass->GetClassVersion() >= 2) {
798  // We know for sure that the user specified the version.
799 
800  if (fOnFileClassVersion >= 2) {
801  // The class version was specified when the object was
802  // written
803 
804  searchOnChecksum = kFALSE;
805 
806  } else {
807  // The class version was not specified when the object was
808  // written OR it was specified to be 1.
809 
810  searchOnChecksum = kTRUE;
811  }
812  } else if (fClass->IsLoaded() && !fClass->IsForeign()) {
813  // We are in the case where the class has a Streamer function.
814  // and fClass->GetClassVersion is 1, we still assume that the
815  // Class Version is specified (to be one).
816 
817  searchOnChecksum = kFALSE;
818 
819  } else if (fClass->IsLoaded() /* implied: && fClass->IsForeign() */ ) {
820  // We are in the case of a Foreign class with no specified
821  // class version.
822 
823  searchOnChecksum = kTRUE;
824 
825  }
826  else {
827  // We are in the case of an 'emulated' class.
828 
829  if (fOnFileClassVersion >= 2) {
830  // The class version was specified when the object was
831  // written
832 
833  searchOnChecksum = kFALSE;
834 
835  } else {
836  // The class version was not specified when the object was
837  // written OR it was specified to be 1.
838 
839  searchOnChecksum = kTRUE;
840 
841  TStreamerInfo* v1 = (TStreamerInfo*) array->At(1);
842  if (v1) {
843  if (fCheckSum != v1->GetCheckSum()) {
844  fClassVersion = array->GetLast() + 1;
845  }
846  }
847  }
848  }
849 
850  if (!searchOnChecksum) {
851  if (fClassVersion < (array->GetEntriesFast() - 1)) {
852  info = (TStreamerInfo*) array->At(fClassVersion);
853  }
854  } else {
855  Int_t ninfos = array->GetEntriesFast() - 1;
856  for (Int_t i = -1; i < ninfos; ++i) {
857  info = (TStreamerInfo*) array->UncheckedAt(i);
858  if (!info) {
859  continue;
860  }
861  if (fCheckSum == info->GetCheckSum() && (info->GetOnFileClassVersion()==1 || info->GetOnFileClassVersion()==0)) {
862  // We must match on the same checksum, an existing TStreamerInfo
863  // for one of the 'unversioned' class layout (i.e. version was 1).
864  fClassVersion = i;
865  break;
866  }
867  info = 0;
868  }
869  if (info==0) {
870  // Find an empty slot.
871  ninfos = array->GetEntriesFast() - 1;
872  Int_t slot = 1; // Start of Class version 1.
873  while ((slot < ninfos) && (array->UncheckedAt(slot) != 0)) {
874  ++slot;
875  }
876  fClassVersion = slot;
877  }
878  }
879 
880  // NOTE: Should we check if the already existing info is the same as
881  // the current one? Yes
882  // In case a class (eg Event.h) has a TClonesArray of Tracks, it could be
883  // that the old info does not have the class name (Track) in the data
884  // member title. Set old title to new title
885  if (info) {
886  // We found an existing TStreamerInfo for our ClassVersion
887  Bool_t match = kTRUE;
888  Bool_t done = kFALSE;
889  Bool_t oldIsNonVersioned = kFALSE;
890  if (fClassVersion!=0 && !fClass->TestBit(TClass::kWarned) && (fClassVersion == info->GetClassVersion()) && (fCheckSum != info->GetCheckSum())) {
891  // The TStreamerInfo's checksum is different from the checksum for the compile class.
892 
893  match = kFALSE;
894  oldIsNonVersioned = info->fOnFileClassVersion==1 && info->fClassVersion != 1;
895 
897  // In the case where the read-in TStreamerInfo does not
898  // match in the 'current' in memory TStreamerInfo for
899  // a non foreign class (we can not get here if this is
900  // a foreign class so we do not need to test it),
901  // we need to add this one more test since the CINT behaviour
902  // with enums changed over time, so verify the checksum ignoring
903  // members of type enum. We also used to not count the //[xyz] comment
904  // in the checksum, so test for that too.
906  &&(info->GetCheckSum() == fClass->GetCheckSum() || fClass->MatchLegacyCheckSum(info->GetCheckSum()))
907  )
908  {
909  match = kTRUE;
910  }
911  if (fOldVersion <= 2) {
912  // Names of STL base classes was modified in vers==3. Allocators removed
913  // (We could be more specific (see test for the same case below)
914  match = kTRUE;
915  }
916  if (!match && CompareContent(0,info,kFALSE,kFALSE,file)) {
917  match = kTRUE;
918  }
919 #ifdef TEST_FOR_BACKWARD_COMPATIBILITY_ABSTRACT_CLASSES
920  if (!match && file->GetVersion() < 51800 && fClass && (fClass->Property() & kIsAbstract)
921  && fClass->GetListOfDataMembers()->GetEntries() != 0)
922  {
923  // In some instances of old files (v5.17 and less), some StreamerInfo for
924  // an abstract class where not written correctly, and add no
925  // data member listed. If in addition one of the data member
926  // was declared using a typedef _and_ the current class definition
927  // uses a different typedef, we are unable to recalculate the
928  // checksum as it was, because the information is missing from
929  // the StreamerInfo, and for the same reason CompareContent can
930  // not know whether this is okay or not ...
931  //
932  // Since this is such an unlikely scenario, let's complain
933  // about it anyway (The class layout *may* have changed, we
934  // don't know).
935 
936  // if (this has only base classes) {
937  // match = kTRUE;
938  // }
939  }
940 #endif
941  } else {
942  // The on-file TStreamerInfo's checksum differs from the checksum of a TStreamerInfo on another file.
943 
944  match = kFALSE;
945  oldIsNonVersioned = info->fOnFileClassVersion==1 && info->fClassVersion != 1;
946 
947  // In the case where the read-in TStreamerInfo does not
948  // match in the 'current' in memory TStreamerInfo for
949  // a non foreign class (we can not get here if this is
950  // a foreign class so we do not need to test it),
951  // we need to add this one more test since the CINT behaviour
952  // with enums changed over time, so verify the checksum ignoring
953  // members of type enum. We also used to not count the //[xyz] comment
954  // in the checksum, so test for that too.
958  || MatchLegacyCheckSum(info->GetCheckSum())
960  {
961  match = kTRUE;
962  }
963  if (fOldVersion <= 2) {
964  // Names of STL base classes was modified in vers==3. Allocators removed
965  // (We could be more specific (see test for the same case below)
966  match = kTRUE;
967  }
968  if (!match && CompareContent(0,info,kFALSE,kFALSE,file)) {
969  match = kTRUE;
970  }
971  }
972  }
973  if (info->IsBuilt()) {
975  fNumber = info->GetNumber();
976  Int_t nel = fElements->GetEntriesFast();
977  TObjArray* elems = info->GetElements();
978  TStreamerElement* e1 = 0;
979  TStreamerElement* e2 = 0;
980  for (Int_t i = 0; i < nel; ++i) {
982  e2 = (TStreamerElement*) elems->At(i);
983  if (!e1 || !e2) {
984  continue;
985  }
986  if (strlen(e1->GetTitle()) != strlen(e2->GetTitle())) {
987  e2->SetTitle(e1->GetTitle());
988  }
989  }
990 
991  done = kTRUE;
992  } else {
994  info = 0;
995  }
996  TString origin;
997  if (!match && !fClass->TestBit(TClass::kWarned)) {
998  if (oldIsNonVersioned) {
999  if (file) {
1000  Warning("BuildCheck", "\n\
1001  The class %s transitioned from not having a specified class version\n\
1002  to having a specified class version (the current class version is %d).\n\
1003  However too many different non-versioned layouts of the class have been\n\
1004  loaded so far. This prevent the proper reading of objects written with\n\
1005  the class layout version %d, in particular from the file:\n\
1006  %s.\n\
1007  To work around this issue, load fewer 'old' files in the same ROOT session.",
1009  } else {
1010  Warning("BuildCheck", "\n\
1011  The class %s transitioned from not having a specified class version\n\
1012  to having a specified class version (the current class version is %d).\n\
1013  However too many different non-versioned layouts of the class have been\n\
1014  loaded so far. This prevent the proper reading of objects written with\n\
1015  the class layout version %d.\n\
1016  To work around this issue, load fewer 'old' files in the same ROOT session.",
1018  }
1019  } else {
1020  if (file) {
1021  if (done) {
1022  Warning("BuildCheck", "\n\
1023  The StreamerInfo for version %d of class %s read from the file %s\n\
1024  has a different checksum than the previously loaded StreamerInfo.\n\
1025  Reading objects of type %s from the file %s \n\
1026  (and potentially other files) might not work correctly.\n\
1027  Most likely the version number of the class was not properly\n\
1028  updated [See ClassDef(%s,%d)].",
1029  fClassVersion, GetName(), file->GetName(), GetName(), file->GetName(), GetName(), fClassVersion);
1030  } else {
1031  Warning("BuildCheck", "\n\
1032  The StreamerInfo from %s does not match existing one (%s:%d)\n\
1033  The existing one has not been used yet and will be discarded.\n\
1034  Reading the file %s will work properly, however writing object of\n\
1035  type %s will not work properly. Most likely the version number\n\
1036  of the class was not properly updated [See ClassDef(%s,%d)].",
1037  file->GetName(), GetName(), fClassVersion,file->GetName(),GetName(), GetName(), fClassVersion);
1038  }
1039  } else {
1040  if (done) {
1041  Warning("BuildCheck", "\n\
1042  The StreamerInfo for version %d of class %s\n\
1043  has a different checksum than the previously loaded StreamerInfo.\n\
1044  Reading objects of type %s\n\
1045  (and potentially other files) might not work correctly.\n\
1046  Most likely the version number of the class was not properly\n\
1047  updated [See ClassDef(%s,%d)].",
1049  } else {
1050  Warning("BuildCheck", "\n\
1051  The StreamerInfo from %s does not match existing one (%s:%d)\n\
1052  The existing one has not been used yet and will be discarded.\n\
1053  Reading should work properly, however writing object of\n\
1054  type %s will not work properly. Most likely the version number\n\
1055  of the class was not properly updated [See ClassDef(%s,%d)].",
1057  }
1058  }
1059  }
1060  CompareContent(0,info,kTRUE,kTRUE,file);
1062  }
1063  if (done) {
1064  return;
1065  }
1066  }
1067  // The slot was free, however it might still be reserved for the current
1068  // loaded version of the class
1069  if (fClass->IsLoaded()
1071  && (fClassVersion != 0) // We don't care about transient classes
1073  && (fCheckSum != fClass->GetCheckSum())) {
1074 
1075  // If the old TStreamerInfo matches the in-memory one when we either
1076  // - ignore the members of type enum
1077  // or
1078  // - ignore the comments annotation (//[xyz])
1079  // we can accept the old TStreamerInfo.
1080 
1082 
1084  if (warn) {
1085  warn = !CompareContent(fClass,0,kFALSE,kFALSE,file);
1086  }
1087 #ifdef TEST_FOR_BACKWARD_COMPATIBILITY_ABSTRACT_CLASSES
1088  if (warn && file->GetVersion() < 51800 && fClass && (fClass->Property() & kIsAbstract)
1089  && fClass->GetListOfDataMembers()->GetEntries() != 0)
1090  {
1091  // In some instances of old files (v5.17 and less), some StreamerInfo for
1092  // an abstract class where not written correctly, and add no
1093  // data member listed. If in addition one of the data member
1094  // was declared using a typedef _and_ the current class definition
1095  // uses a different typedef, we are unable to recalculate the
1096  // checksum as it was, because the information is missing from
1097  // the StreamerInfo, and for the same reason CompareContent can
1098  // not know whether this is okay or not ...
1099  //
1100  // Since this is such an unlikely scenario, let's complain
1101  // about it anyway (The class layout *may* have changed, we
1102  // don't know).
1103 
1104  // if (this has only base classes) {
1105  // warn = kFALSE;
1106  // }
1107  }
1108 #endif // TEST_FOR_BACKWARD_COMPATIBILITY
1109  if (warn && (fOldVersion <= 2)) {
1110  // Names of STL base classes was modified in vers==3. Allocators removed
1111  //
1112  TIter nextBC(fClass->GetListOfBases());
1113  TBaseClass* bc = 0;
1114  while ((bc = (TBaseClass*) nextBC())) {
1115  if (bc->GetClassPointer()->GetCollectionType()) {
1116  warn = kFALSE;
1117  }
1118  }
1119  }
1120  if (warn) {
1121  if (file) {
1122  Warning("BuildCheck", "\n\
1123  The StreamerInfo of class %s read from file %s\n\
1124  has the same version (=%d) as the active class but a different checksum.\n\
1125  You should update the version to ClassDef(%s,%d).\n\
1126  Do not try to write objects with the current class definition,\n\
1127  the files will not be readable.\n", GetName(), file->GetName(), fClassVersion, GetName(), fClassVersion + 1);
1128  } else {
1129  Warning("BuildCheck", "\n\
1130  The StreamerInfo of class %s \n\
1131  has the same version (=%d) as the active class but a different checksum.\n\
1132  You should update the version to ClassDef(%s,%d).\n\
1133  Do not try to write objects with the current class definition,\n\
1134  the files will not be readable.\n", GetName(), fClassVersion, GetName(), fClassVersion + 1);
1135  }
1136  CompareContent(fClass,0,kTRUE,kTRUE,file);
1138  }
1139  } else {
1140  if (!fClass->IsVersioned()) {
1141  Fatal("BuildCheck", "\n\
1142  The StreamerInfo of unversioned class %s \n\
1143  has the same version (=%d) as the active class but an old checksum.\n\
1144  This should not happen. An assert will follow.\n", GetName(), fClassVersion);
1145  }
1146  }
1147  }
1148  if (!fClass->IsLoaded() && this->fOnFileClassVersion>1)
1149  {
1150  ROOT::ResetClassVersion(fClass,(const char*)-1, this->fClassVersion);
1151  }
1152  }
1153  // FIXME: This code can never execute because Build() calls
1154  // TStreamerElement::Class()->IgnoreTObjectStreamer()
1155  // so our bits are never saved to the file.
1158  }
1159  if ((fClassVersion < -1) || (fClassVersion > 65000)) {
1160  printf("ERROR reading TStreamerInfo: %s fClassVersion=%d\n", GetName(), fClassVersion);
1161  SetBit(kCanDelete);
1162  fNumber = -1;
1163  return;
1164  }
1165 
1168  && GetCheckSum() != fClass->GetCheckSum()
1170  // We got here, thus we are a perfect alias for the current streamerInfo,
1171  // but we might had odd v5 style name spelling, so let's prefer the
1172  // current one.
1173  SetBit(kCanDelete);
1174  return;
1175  }
1176 
1178  ++fgCount;
1179  fNumber = fgCount;
1180 
1181  // Since we just read this streamerInfo from file, it has already been built.
1182  fIsBuilt = kTRUE;
1183 
1184  //add to the global list of StreamerInfo
1185  TObjArray* infos = (TObjArray*) gROOT->GetListOfStreamerInfo();
1186  infos->AddAtAndExpand(this, fNumber);
1187 }
1188 
1189 ////////////////////////////////////////////////////////////////////////////////
1190 /// Create an Emulation TStreamerInfo object.
1191 
1193 {
1195 
1196  TString duName;
1197  R__ASSERT(file);
1198  Int_t fv = file->GetVersion()%100000;
1199  R__ASSERT(fv < 30000);
1200  fClassVersion = -1;
1201  fCheckSum = 2001;
1202  TObjArray *elements = GetElements();
1203  Int_t ndata = elements ? elements->GetEntries() : 0;
1204  for (Int_t i=0;i < ndata;i++) {
1205  TStreamerElement *element = (TStreamerElement*)elements->UncheckedAt(i);
1206  if (!element) break;
1207  int ty = element->GetType();
1208  if (ty < kChar || ty >kULong+kOffsetL) continue;
1209  if (ty == kLong) element->SetType(kInt);
1210  if (ty == kULong) element->SetType(kUInt);
1211  if (ty == kLong + kOffsetL) element->SetType(kInt + kOffsetL);
1212  if (ty == kULong + kOffsetL) element->SetType(kUInt + kOffsetL);
1213  if (ty <= kULong) continue;
1214  duName = element->GetName();
1215  duName.Append("QWERTY");
1216  TStreamerBasicType *bt = new TStreamerBasicType(duName, "", 0, kInt,"Int_t");
1217  {for (int j=ndata-1;j>=i;j--) {elements->AddAtAndExpand(elements->At(j),j+1);}}
1218  elements->AddAt(bt,i);
1219  ndata++;
1220  i++;
1221  }
1222  BuildOld();
1223 }
1224 
1225 ////////////////////////////////////////////////////////////////////////////////
1226 /// Check if we can build this for foreign class - do we have some rules
1227 /// to do that.
1228 
1229 Bool_t TStreamerInfo::BuildFor( const TClass *in_memory_cl )
1230 {
1232 
1233  if( !in_memory_cl || !in_memory_cl->GetSchemaRules() ) {
1234  return kFALSE;
1235  }
1236 
1237  auto rules = in_memory_cl->GetSchemaRules()->FindRules( GetName(), fOnFileClassVersion, fCheckSum );
1238 
1239  if( rules.empty() && !in_memory_cl->GetCollectionType() ) {
1240  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() );
1241  return kFALSE;
1242  }
1243 
1244  fClass = const_cast<TClass*>(in_memory_cl);
1245 
1246  return kTRUE;
1247 }
1248 
1249 
1250 namespace {
1251 ////////////////////////////////////////////////////////////////////////////////
1252 /// Helper function for BuildOld
1253  Bool_t ClassWasMovedToNamespace(TClass *oldClass, TClass *newClass)
1254  {
1255  // Returns true if oldClass is the same as newClass but newClass is in a
1256  // namespace (and oldClass was not in a namespace).
1257 
1258  if (oldClass == 0 || newClass == 0) return kFALSE;
1259 
1260  UInt_t newlen = strlen(newClass->GetName());
1261  UInt_t oldlen = strlen(oldClass->GetName());
1262 
1263  const char *oldname = oldClass->GetName();
1264  for (UInt_t i = oldlen, done = false, nest = 0; (i>0) && !done ; --i) {
1265  switch (oldClass->GetName()[i-1]) {
1266  case '>' : ++nest; break;
1267  case '<' : if (nest==0) return kFALSE; // the name is not well formed, give up.
1268  --nest; break;
1269  case ':' : if (nest == 0) oldname= &(oldClass->GetName()[i]); done = kTRUE; break;
1270  }
1271  }
1272  oldlen = strlen(oldname);
1273  if (!(strlen(newClass->GetName()) > strlen(oldClass->GetName()))) {
1274  return kFALSE;
1275  }
1276 
1277  const char* newEnd = & (newClass->GetName()[newlen-oldlen]);
1278 
1279  if (0 != strcmp(newEnd, oldname)) {
1280  return kFALSE;
1281  }
1282 
1283  Int_t oldv = oldClass->GetStreamerInfo()->GetClassVersion();
1284 
1285  if (newClass->GetStreamerInfos() && oldv < newClass->GetStreamerInfos()->GetSize() && newClass->GetStreamerInfos()->At(oldv) && strcmp(newClass->GetStreamerInfos()->At(oldv)->GetName(), oldClass->GetName()) != 0) {
1286  // The new class has already a TStreamerInfo for the the same version as
1287  // the old class and this was not the result of an import. So we do not
1288  // have a match
1289  return kFALSE;
1290  }
1291  return kTRUE;
1292  }
1293 
1294 ////////////////////////////////////////////////////////////////////////////////
1295 /// Import the streamerInfo from oldClass to newClass.
1296 ///
1297 /// In case of conflict, returns the version number of the StreamerInfo
1298 /// with the conflict.
1299 /// Return 0 in case of success
1300  Int_t ImportStreamerInfo(TClass *oldClass, TClass *newClass) {
1301 
1302  TIter next(oldClass->GetStreamerInfos());
1303  TStreamerInfo *info;
1304  while ((info = (TStreamerInfo*)next())) {
1305  info = (TStreamerInfo*)info->Clone();
1306  if (!info) {
1307  Error("ImportStreamerInfo","Unable to clone the StreamerInfo for %s.",(*next)->GetName());
1308  } else {
1309  info->SetClass(newClass);
1310  Int_t oldv = info->GetClassVersion();
1311  if (oldv > newClass->GetStreamerInfos()->GetSize() || newClass->GetStreamerInfos()->At(oldv) == 0) {
1312  // All is good.
1313  newClass->RegisterStreamerInfo(info);
1314  } else {
1315  // We verify that we are consistent and that
1316  // newcl->GetStreamerInfos()->UncheckedAt(info->GetClassVersion)
1317  // is already the same as info.
1318  if (strcmp(newClass->GetStreamerInfos()->At(oldv)->GetName(),
1319  oldClass->GetName()) != 0) {
1320  // The existing StreamerInfo does not already come from OldClass.
1321  // This is a real problem!
1322  return oldv;
1323  }
1324  }
1325  }
1326  }
1327  return 0;
1328  }
1329 
1330  Bool_t ContainerMatchTClonesArray(TClass *newClass)
1331  {
1332  // Return true if newClass is a likely valid conversion from
1333  // a TClonesArray
1334 
1335  return newClass->GetCollectionProxy()
1336  && newClass->GetCollectionProxy()->GetValueClass()
1337  && !newClass->GetCollectionProxy()->HasPointers();
1338  }
1339 
1340  Bool_t CollectionMatch(const TClass *oldClass, const TClass* newClass)
1341  {
1342  // Return true if oldClass and newClass points to 2 compatible collection.
1343  // i.e. they contains the exact same type.
1344 
1345  TVirtualCollectionProxy *oldProxy = oldClass->GetCollectionProxy();
1346  TVirtualCollectionProxy *newProxy = newClass->GetCollectionProxy();
1347 
1348  TClass *oldContent = oldProxy->GetValueClass();
1349  TClass *newContent = newProxy->GetValueClass();
1350 
1351  Bool_t contentMatch = kFALSE;
1352  if (oldContent) {
1353  if (oldContent == newContent) {
1354  contentMatch = kTRUE;
1355  } else if (newContent) {
1356  TString oldFlatContent( TMakeProject::UpdateAssociativeToVector(oldContent->GetName()) );
1357  TString newFlatContent( TMakeProject::UpdateAssociativeToVector(newContent->GetName()) );
1358  if (oldFlatContent == newFlatContent) {
1359  contentMatch = kTRUE;
1360  }
1361  } else {
1362  contentMatch = kFALSE;
1363  }
1364  } else {
1365  contentMatch = (newContent==0);
1366  }
1367 
1368  if (contentMatch) {
1369  if ((oldContent==0 && oldProxy->GetType() == newProxy->GetType())
1370  ||(oldContent && oldProxy->HasPointers() == newProxy->HasPointers())) {
1371  // We have compatibles collections (they have the same content)!
1372  return kTRUE;
1373  }
1374  }
1375  return kFALSE;
1376  }
1377 
1378  Bool_t CollectionMatchFloat16(const TClass *oldClass, const TClass* newClass)
1379  {
1380  // Return true if oldClass and newClass points to 2 compatible collection.
1381  // i.e. they contains the exact same type.
1382 
1383  TVirtualCollectionProxy *oldProxy = oldClass->GetCollectionProxy();
1384  TVirtualCollectionProxy *newProxy = newClass->GetCollectionProxy();
1385 
1386  if (oldProxy->GetValueClass() == 0 && newProxy->GetValueClass() == 0
1387  && (oldProxy->GetType() == kFloat_t || oldProxy->GetType() == kFloat16_t)
1388  && (newProxy->GetType() == kFloat_t || newProxy->GetType() == kFloat16_t )) {
1389  // We have compatibles collections (they have the same content)!
1390  return (oldClass->GetCollectionType() == newClass->GetCollectionType());
1391  }
1392  return kFALSE;
1393  }
1394 
1395  Bool_t CollectionMatchDouble32(const TClass *oldClass, const TClass* newClass)
1396  {
1397  // Return true if oldClass and newClass points to 2 compatible collection.
1398  // i.e. they contains the exact same type.
1399 
1400  TVirtualCollectionProxy *oldProxy = oldClass->GetCollectionProxy();
1401  TVirtualCollectionProxy *newProxy = newClass->GetCollectionProxy();
1402 
1403  if (oldProxy->GetValueClass() == 0 && newProxy->GetValueClass() == 0
1404  && (oldProxy->GetType() == kDouble_t || oldProxy->GetType() == kDouble32_t)
1405  && (newProxy->GetType() == kDouble_t || newProxy->GetType() == kDouble32_t )) {
1406  // We have compatibles collections (they have the same content)!
1407  return (oldClass->GetCollectionType() == newClass->GetCollectionType());
1408  }
1409  return kFALSE;
1410  }
1411 
1412  Bool_t CollectionMatchLong64(const TClass *oldClass, const TClass* newClass)
1413  {
1414  // Return true if oldClass and newClass points to 2 compatible collection.
1415  // i.e. they contains the exact same type.
1416 
1417  TVirtualCollectionProxy *oldProxy = oldClass->GetCollectionProxy();
1418  TVirtualCollectionProxy *newProxy = newClass->GetCollectionProxy();
1419 
1420  if (oldProxy->GetValueClass() == 0 && newProxy->GetValueClass() == 0
1421  && (oldProxy->GetType() == kLong_t || oldProxy->GetType() == kLong64_t)
1422  && (newProxy->GetType() == kLong_t || newProxy->GetType() == kLong64_t )) {
1423  // We have compatibles collections (they have the same content)!
1424  return (oldClass->GetCollectionType() == newClass->GetCollectionType());
1425  }
1426  return kFALSE;
1427  }
1428 
1429  Bool_t CollectionMatchULong64(const TClass *oldClass, const TClass* newClass)
1430  {
1431  // Return true if oldClass and newClass points to 2 compatible collection.
1432  // i.e. they contains the exact same type.
1433 
1434  TVirtualCollectionProxy *oldProxy = oldClass->GetCollectionProxy();
1435  TVirtualCollectionProxy *newProxy = newClass->GetCollectionProxy();
1436 
1437  if (oldProxy->GetValueClass() == 0 && newProxy->GetValueClass() == 0
1438  && (oldProxy->GetType() == kULong_t || oldProxy->GetType() == kULong64_t)
1439  && (newProxy->GetType() == kULong_t || newProxy->GetType() == kULong64_t )) {
1440  // We have compatibles collections (they have the same content)!
1441  return (oldClass->GetCollectionType() == newClass->GetCollectionType());
1442  }
1443  return kFALSE;
1444  }
1445 
1446  TClass *FindAlternate(TClass *context, const std::string &i_name, std::string& newName)
1447  {
1448  // Return a class whose has the name as oldClass and can be found
1449  // within the scope of the class 'context'.
1450 
1451  // First strip any 'const ' prefix or trailing '*'.
1452  std::string name(i_name);
1453  newName.clear();
1454  if (name.compare(0,6,"const ")==0) {
1455  newName = "const ";
1456  name.erase(0,6);
1457  }
1458  std::string suffix;
1459  UInt_t nstars = 0;
1460  while(name[name.length()-nstars-1]=='*') {
1461  ++nstars;
1462  suffix.append("*");
1463  }
1464  if (nstars) {
1465  name.erase(name.length()-nstars,nstars);
1466  }
1467 
1468  std::string alternate(context->GetName());
1469  alternate.append("::");
1470  alternate.append(name);
1471 
1472  TClass *altcl = TClass::GetClass(alternate.c_str(),/*load=*/ false,true);
1473  if (altcl) {
1474  newName.append(altcl->GetName());
1475  newName.append(suffix);
1476  return altcl;
1477  }
1478 
1479  size_t ctxt_cursor = strlen(context->GetName());
1480  for (size_t level = 0; ctxt_cursor != 0; --ctxt_cursor) {
1481  switch (context->GetName()[ctxt_cursor]) {
1482  case '<': --level; break;
1483  case '>': ++level; break;
1484  case ':': if (level == 0) {
1485  // we encountered a scope not within a template
1486  // parameter.
1487  alternate.clear();
1488  alternate.append(context->GetName(),ctxt_cursor+1);
1489  alternate.append(name);
1490  altcl = TClass::GetClass(alternate.c_str(),/*load=*/ false,true);
1491  if (altcl) {
1492  newName.append(altcl->GetName());
1493  newName.append(suffix);
1494  return altcl;
1495  }
1496  }
1497  }
1498  }
1499  newName.clear();
1500  return 0;
1501  }
1502 
1503  TClass *FixCollectionV5(TClass *context, TClass *oldClass, TClass *newClass)
1504  {
1505  assert(oldClass->GetCollectionProxy() && newClass->GetCollectionProxy());
1506 
1507  TVirtualCollectionProxy *old = oldClass->GetCollectionProxy();
1508  TVirtualCollectionProxy *current = newClass->GetCollectionProxy();
1509  Int_t stlkind = old->GetCollectionType();
1510 
1511  if (stlkind == ROOT::kSTLmap || stlkind == ROOT::kSTLmultimap) {
1512 
1513  if (current->GetValueClass() == nullptr) {
1514  // This should really never happen (the content of map should always
1515  // be a pair and thus have a TClass ... so let's just give up ...
1516  // It actually happens in the case where one of the member is an
1517  // enum that is part of dictionary payload that is not yet
1518  // autoloaded.
1519  return nullptr;
1520  }
1521  TVirtualStreamerInfo *info = current->GetValueClass()->GetStreamerInfo();
1522  if (info->GetElements()->GetEntries() != 2) {
1523  return oldClass;
1524  }
1525  TStreamerElement *f = (TStreamerElement*) info->GetElements()->At(0);
1526  TStreamerElement *s = (TStreamerElement*) info->GetElements()->At(1);
1527 
1528  info = old->GetValueClass()->GetStreamerInfo();
1529  assert(info->GetElements()->GetEntries() == 2);
1530  TStreamerElement *of = (TStreamerElement*) info->GetElements()->At(0);
1531  TStreamerElement *os = (TStreamerElement*) info->GetElements()->At(1);
1532 
1533  TClass *firstNewCl = f ? f->GetClass() : 0;
1534  TClass *secondNewCl = s ? s->GetClass() : 0;
1535 
1536  TClass *firstOldCl = of ? of->GetClass() : 0;
1537  TClass *secondOldCl = os ? os->GetClass() : 0;
1538 
1539  if ((firstNewCl && !firstOldCl) || (secondNewCl && !secondOldCl))
1540  {
1541  std::vector<std::string> inside;
1542  int nestedLoc;
1543  TClassEdit::GetSplit( oldClass->GetName(), inside, nestedLoc, TClassEdit::kLong64 );
1544 
1545  TClass *firstAltCl = firstOldCl;
1546  TClass *secondAltCl = secondOldCl;
1547  std::string firstNewName;
1548  std::string secondNewName;
1549  if (firstNewCl && !firstOldCl) {
1550  firstAltCl = FindAlternate(context, inside[1], firstNewName);
1551  }
1552  if (secondNewCl && !secondOldCl) {
1553  secondAltCl = FindAlternate(context, inside[2], secondNewName);
1554  }
1555  if ((firstNewCl && firstAltCl != firstOldCl) ||
1556  (secondNewCl && secondAltCl != secondOldCl) ) {
1557 
1558  // Need to produce new name.
1559  std::string alternate = inside[0];
1560  alternate.append("<");
1561  alternate.append(firstAltCl ? firstNewName : inside[1]);
1562  alternate.append(",");
1563  alternate.append(secondAltCl? secondNewName : inside[2]);
1564  // We are intentionally dropping any further arguments,
1565  // they would be using the wrong typename and would also be
1566  // somewhat superflous since this is for the old layout.
1567  if (alternate[alternate.length()-1]=='>') {
1568  alternate.append(" ");
1569  }
1570  alternate.append(">");
1571  return TClass::GetClass(alternate.c_str(),true,true);
1572  }
1573  }
1574 
1575  } else if (current->GetValueClass() && !old->GetValueClass()
1576  && old->GetType() == kInt_t) {
1577 
1578  // The old CollectionProxy claims it contains int (or enums) while
1579  // the new one claims to contain a class. It is likely that we have
1580  // in the collection name a class (typedef) name that is missing its
1581  // scope. Let's try to check.
1582 
1583  std::vector<std::string> inside;
1584  int nestedLoc;
1585  TClassEdit::GetSplit( oldClass->GetName(), inside, nestedLoc, TClassEdit::kLong64 );
1586 
1587  // Now let's if we can find this missing type.
1588  std::string newName;
1589  TClass *altcl = FindAlternate(context, inside[1], newName);
1590 
1591  if (altcl) {
1592  std::string alternate = inside[0];
1593  alternate.append("<");
1594  alternate.append(newName);
1595  // We are intentionally dropping any further arguments,
1596  // they would be using the wrong typename and would also be
1597  // somewhat superflous since this is for the old layout.
1598  if (alternate[alternate.length()-1]=='>') {
1599  alternate.append(" ");
1600  }
1601  alternate.append(">");
1602  return TClass::GetClass(alternate.c_str(),true,true);
1603  }
1604  }
1605  return 0;
1606  }
1607 
1608  // Makes sure kBuildOldUsed set once BuildOld finishes
1609  struct TBuildOldGuard {
1610  TBuildOldGuard(TStreamerInfo* info): fInfo(info) {
1611  fInfo->SetBit(TStreamerInfo::kBuildRunning);
1612  }
1613  ~TBuildOldGuard() {
1614  fInfo->ResetBit(TStreamerInfo::kBuildRunning);
1615  fInfo->SetBit(TStreamerInfo::kBuildOldUsed);
1616  }
1617  TStreamerInfo* fInfo;
1618  };
1619 }
1620 
1621 ////////////////////////////////////////////////////////////////////////////////
1622 /// rebuild the TStreamerInfo structure
1623 
1625 {
1627 
1628  if ( TestBit(kBuildOldUsed) ) return;
1629 
1630  // Are we recursing on ourself?
1632 
1633  // This is used to avoid unwanted recursive call to Build and make sure
1634  // that we record the execution of BuildOld.
1635  TBuildOldGuard buildOldGuard(this);
1636 
1637  if (gDebug > 0) {
1638  printf("\n====>Rebuilding TStreamerInfo for class: %s, version: %d\n", GetName(), fClassVersion);
1639  }
1640 
1641  Bool_t wasCompiled = IsCompiled();
1642 
1643  if (fClass->GetClassVersion() == fClassVersion) {
1644  if (!fClass->HasInterpreterInfo() || fClass->GetCollectionType() || TClassEdit::IsSTLBitset(GetName()))
1645  {
1646  // Handle emulated classes and STL containers specially.
1647  // in this case BuildRealData would call BuildOld for this same
1648  // TStreamerInfo to be able to build the real data on it.
1649  } else {
1650  fClass->BuildRealData();
1651  }
1652  }
1653  else {
1654  // This is to support the following case
1655  // Shared library: Event v2
1656  // calling cl->GetStreamerInfo(1)->BuildOld(); (or equivalent)
1657  // which calls cl->BuildReadData()
1658  // which set fRealData to some value
1659  // then call Event()
1660  // which call cl->GetStreamerInfo()
1661  // which call cl->BuildRealData();
1662  // which returns immediately (upon seeing fRealData!=0)
1663  // then the main StreamerInfo build using the partial content of fRealData
1664  // then BuildRealData returns
1665  // then GetStreamerInfo() returns
1666  // then Event() returns
1667  // then fRealData is finished being populated
1668  // then this function continue,
1669  // then it uses the main streamerInfo
1670  // .... which is incomplete.
1671  //
1672  // Instead we force the creation of the main streamerInfo object
1673  // before the creation of fRealData.
1675  }
1676 
1677  TIter next(fElements);
1678  TStreamerElement* element;
1679  Int_t offset = 0;
1680  TMemberStreamer* streamer = 0;
1681 
1682  constexpr size_t kSizeOfPtr = sizeof(void*);
1683 
1684  int nBaze = 0;
1685 
1686  if ((fElements->GetEntries() == 1) && !strcmp(fElements->At(0)->GetName(), "This")) {
1687  if (fClass->GetCollectionProxy()) {
1688  element = (TStreamerElement*)next();
1689  element->SetNewType( element->GetType() );
1690  element->SetNewClass( fClass );
1691  } else if (((TStreamerElement*)fElements->At(0))->GetType() == TStreamerInfo::kSTL &&
1692  strcmp( ((TStreamerElement*)fElements->At(0))->GetTypeName(),GetName()) != 0) {
1693  // We have a collection that was proxied but does not have a collection proxy,
1694  // let's put one in place just for fun ... humm however we have no clue what is the value
1695  // type ....
1696 
1697  // For now wild guess ....
1698 
1699  }
1700  }
1701 
1702  TClass *allocClass = 0;
1703  TStreamerInfo *infoalloc = 0;
1704 
1705  //---------------------------------------------------------------------------
1706  // Get schema rules for this class
1707  /////////////////////////////////////////////////////////////////////////////
1708 
1709  ROOT::TSchemaRuleSet::TMatches rules;
1710  const ROOT::TSchemaRuleSet* ruleSet = fClass->GetSchemaRules();
1711 
1712  if (ruleSet) rules = ruleSet->FindRules( GetName(), fOnFileClassVersion, fCheckSum );
1713 
1714  Bool_t shouldHaveInfoLoc = fClass->TestBit(TClass::kIsEmulation) && !TClassEdit::IsStdClass(fClass->GetName());
1715  Int_t virtualInfoLocAlloc = 0;
1716  fNVirtualInfoLoc = 0;
1717  delete [] fVirtualInfoLoc;
1718  fVirtualInfoLoc = 0;
1719 
1720  while ((element = (TStreamerElement*) next())) {
1721  if (element->IsA()==TStreamerArtificial::Class()
1722  || element->TestBit(TStreamerElement::kCache) )
1723  {
1724  // Prevent BuildOld from modifying existing ArtificialElement (We need to review when and why BuildOld
1725  // needs to be re-run; it might be needed if the 'current' class change (for example from being an onfile
1726  // version to being a version loaded from a shared library) and we thus may have to remove the artifical
1727  // element at the beginning of BuildOld)
1728 
1729  continue;
1730  };
1731 
1732  element->SetNewType(element->GetType());
1733  if (element->IsBase()) {
1734  //---------------------------------------------------------------------
1735  // Dealing with nonSTL bases
1736  ///////////////////////////////////////////////////////////////////////
1737 
1738  if (element->IsA() == TStreamerBase::Class()) {
1739  TStreamerBase* base = (TStreamerBase*) element;
1740 #if defined(PROPER_IMPLEMEMANTION_OF_BASE_CLASS_RENAMING)
1741  TClass* baseclass = fClass->GetBaseClass( base->GetName() );
1742 #else
1743  // Currently the base class renaming does not work, so we use the old
1744  // version of the code which essentially disable the next if(!baseclass ..
1745  // statement.
1746  TClass* baseclass = base->GetClassPointer();
1747 #endif
1748 
1749  //------------------------------------------------------------------
1750  // We do not have this base class - check if we're renaming
1751  ////////////////////////////////////////////////////////////////////
1752 
1753  if( !baseclass && !fClass->TestBit( TClass::kIsEmulation ) ) {
1754  const ROOT::TSchemaRule* rule = (rules ? rules.GetRuleWithSource( base->GetName() ) : 0);
1755 
1756  //---------------------------------------------------------------
1757  // No renaming, sorry
1758  /////////////////////////////////////////////////////////////////
1759 
1760  if( !rule ) {
1761  Error("BuildOld", "Could not find base class: %s for %s and could not find any matching rename rule\n", base->GetName(), GetName());
1762  continue;
1763  }
1764 
1765  //----------------------------------------------------------------
1766  // Find a new target class
1767  /////////////////////////////////////////////////////////////////
1768 
1769  const TObjArray* targets = rule->GetTarget();
1770  if( !targets ) {
1771  Error("BuildOld", "Could not find base class: %s for %s, renaming rule was found but is malformed\n", base->GetName(), GetName());
1772  }
1773  TString newBaseClass = ((TObjString*)targets->At(0))->GetString();
1774  baseclass = TClass::GetClass( newBaseClass );
1775  base->SetNewBaseClass( baseclass );
1776  }
1777  //-------------------------------------------------------------------
1778  // No base class in emulated mode
1779  ////////////////////////////////////////////////////////////////////
1780 
1781  else if( !baseclass ) {
1782  baseclass = base->GetClassPointer();
1783  if (!baseclass) {
1784  Warning("BuildOld", "Missing base class: %s skipped", base->GetName());
1785  // FIXME: Why is the version number 1 here? Answer: because we don't know any better at this point
1786  baseclass = new TClass(element->GetName(), 1, 0, 0, -1, -1);
1787  element->Update(0, baseclass);
1788  }
1789  }
1790  baseclass->BuildRealData();
1791 
1792  // Calculate the offset using the 'real' base class name (as opposed to the
1793  // '@@emulated' in the case of the emulation of an abstract base class.
1794  Int_t baseOffset = fClass->GetBaseClassOffset(baseclass);
1795 
1796  // Deal with potential schema evolution (renaming) of the base class.
1797  if (baseOffset < 0) {
1798 
1799  // See if this base element can be converted into one of
1800  // the existing base class.
1801  TList* listOfBases = fClass->GetListOfBases();
1802  if (listOfBases) {
1803  TBaseClass* bc = 0;
1804  TIter nextBC(fClass->GetListOfBases());
1805  while ((bc = (TBaseClass*) nextBC())) {
1806  TClass *in_memory_bcl = bc->GetClassPointer();
1807  if (in_memory_bcl && in_memory_bcl->GetSchemaRules()) {
1808  auto baserule = in_memory_bcl->GetSchemaRules()->FindRules( base->GetName(), base->GetBaseVersion(), base->GetBaseCheckSum() );
1809  if (!baserule.empty()) {
1810  base->SetNewBaseClass(in_memory_bcl);
1811  baseOffset = bc->GetDelta();
1812 
1813  }
1814  }
1815  }
1816  }
1817  }
1818  // We need to initialize the element now, as we need the
1819  // correct StreamerInfo next.
1820  element->Init(this);
1821 
1822  // Force the StreamerInfo "Compilation" of the base classes first. This is necessary in
1823  // case the base class contains a member used as an array dimension in the derived classes.
1824  TStreamerInfo* infobase;
1825  if (fClass->TestBit(TClass::kIsEmulation) && (baseclass->Property() & kIsAbstract)) {
1826  Int_t version = base->GetBaseVersion();
1827  if (version >= 0 || base->GetBaseCheckSum() == 0) {
1828  infobase = (TStreamerInfo*)baseclass->GetStreamerInfoAbstractEmulated(version);
1829  } else {
1830  infobase = (TStreamerInfo*)baseclass->FindStreamerInfoAbstractEmulated(base->GetBaseCheckSum());
1831  }
1832  if (infobase) baseclass = infobase->GetClass();
1833  }
1834  else {
1835  infobase = (TStreamerInfo*)base->GetBaseStreamerInfo();
1836  }
1837 
1838  if (infobase && infobase->fComp == 0) {
1839  infobase->BuildOld();
1840  }
1841 
1842  if (infobase && shouldHaveInfoLoc && baseclass->TestBit(TClass::kIsEmulation) ) {
1843  if ( (fNVirtualInfoLoc + infobase->fNVirtualInfoLoc) > virtualInfoLocAlloc ) {
1844  ULong_t *store = fVirtualInfoLoc;
1845  virtualInfoLocAlloc = 16 * ( (fNVirtualInfoLoc + infobase->fNVirtualInfoLoc) / 16 + 1);
1846  fVirtualInfoLoc = new ULong_t[virtualInfoLocAlloc];
1847  if (store) {
1848  memcpy(fVirtualInfoLoc, store, sizeof(ULong_t)*fNVirtualInfoLoc);
1849  delete [] store;
1850  }
1851  }
1852  for (int nloc = 0; nloc < infobase->fNVirtualInfoLoc; ++nloc) {
1853  fVirtualInfoLoc[ fNVirtualInfoLoc + nloc ] = baseOffset + infobase->fVirtualInfoLoc[nloc];
1854  }
1855  fNVirtualInfoLoc += infobase->fNVirtualInfoLoc;
1856  }
1857 
1858 
1859  {
1860  if (baseOffset < 0) {
1861  element->SetNewType(-1);
1862  }
1863  }
1864  element->SetOffset(baseOffset);
1865  offset += baseclass->Size();
1866 
1867  continue;
1868  } else {
1869  // Not a base elem but still base, string or STL as a base
1870  nBaze++;
1871  TList* listOfBases = fClass->GetListOfBases();
1872  Int_t baseOffset = -1;
1873  Int_t asize = 0;
1874  if (listOfBases) {
1875  // Do a search for the classname and some of its alternatives spelling.
1876 
1877  TBaseClass* bc = 0;
1878  TIter nextBC(fClass->GetListOfBases());
1879  while ((bc = (TBaseClass*) nextBC())) {
1880  if (strchr(bc->GetName(), '<') || !strcmp(bc->GetName(),"string")) {
1881  TString bcName(TClassEdit::ShortType(bc->GetName(), TClassEdit::kDropStlDefault).c_str());
1882  TString elName(TClassEdit::ShortType(element->GetTypeName(), TClassEdit::kDropStlDefault).c_str());
1883  if (bcName == elName) {
1884  break;
1885  }
1886  }
1887  }
1888 
1889  if (!bc) {
1890  // Error("BuildOld", "Could not find STL base class: %s for %s\n", element->GetName(), GetName());
1891  offset = kMissing;
1892  element->SetOffset(kMissing);
1893  element->SetNewType(-1);
1894  continue;
1895  } else if (bc->GetClassPointer()->GetCollectionProxy()
1896  && !bc->GetClassPointer()->IsLoaded()
1897  && bc->GetClassPointer()->GetCollectionProxy()->GetCollectionType() != ROOT::kSTLvector) {
1898  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());
1899  offset = kMissing;
1900  element->SetOffset(kMissing);
1901  element->SetNewType(-1);
1902  continue;
1903  }
1904  baseOffset = bc->GetDelta();
1905  asize = bc->GetClassPointer()->Size();
1906 
1907  } else if (fClass->TestBit( TClass::kIsEmulation )) {
1908  // Do a search for the classname and some of its alternatives spelling.
1909 
1911  if (newInfo == this) {
1912  baseOffset = offset;
1913  asize = element->GetSize();
1914  } else if (newInfo) {
1915  TIter newElems( newInfo->GetElements() );
1916  TStreamerElement *newElement;
1917  while( (newElement = (TStreamerElement*)newElems()) ) {
1918  const char *newElName = newElement->GetName();
1919  if (newElement->IsBase() && (strchr(newElName,'<') || !strcmp(newElName,"string")) ) {
1920  TString bcName(TClassEdit::ShortType(newElName, TClassEdit::kDropStlDefault).c_str());
1921  TString elName(TClassEdit::ShortType(element->GetTypeName(), TClassEdit::kDropStlDefault).c_str());
1922  if (bcName == elName) {
1923  break;
1924  }
1925  }
1926  }
1927  if (!newElement) {
1928  Error("BuildOld", "Could not find STL base class: %s for %s\n", element->GetName(), GetName());
1929  continue;
1930  }
1931  baseOffset = newElement->GetOffset();
1932  asize = newElement->GetSize();
1933  }
1934  }
1935  if (baseOffset == -1) {
1936  TClass* cb = element->GetClassPointer();
1937  if (!cb) {
1938  element->SetNewType(-1);
1939  continue;
1940  }
1941  asize = cb->Size();
1942  baseOffset = fClass->GetBaseClassOffset(cb);
1943  }
1944 
1945  // we know how to read but do we know where to read?
1946  if (baseOffset < 0) {
1947  element->SetNewType(-1);
1948  continue;
1949  }
1950  element->SetOffset(baseOffset);
1951  offset += asize;
1952  element->Init(this);
1953  continue;
1954  } // if element is of type TStreamerBase or not.
1955  } // if (element->IsBase())
1956 
1957  // If we get here, this means that we looked at all the base classes.
1958  if (shouldHaveInfoLoc && fNVirtualInfoLoc==0) {
1959  fNVirtualInfoLoc = 1;
1960  fVirtualInfoLoc = new ULong_t[1]; // To allow for a single delete statement.
1961  fVirtualInfoLoc[0] = offset;
1962  offset += sizeof(TStreamerInfo*);
1963  }
1964 
1965  TDataMember* dm = 0;
1966 
1967  std::string typeNameBuf;
1968  const char* dmType = nullptr;
1969  Bool_t dmIsPtr = false;
1970  Bool_t isUniquePtr = false;
1971  TDataType* dt(nullptr);
1972  Int_t ndim = 0 ; //dm->GetArrayDim();
1973  std::array<Int_t, 5> maxIndices; // 5 is the maximum supported in TStreamerElement::SetMaxIndex
1974  Bool_t isStdArray(kFALSE);
1975 
1976  // First set the offset and sizes.
1977  if (fClass->GetState() <= TClass::kEmulated) {
1978  // Note the initilization in this case are
1979  // delayed until __after__ the schema evolution
1980  // section, just in case the info has changed.
1981 
1982  // We are in the emulated case
1983  streamer = 0;
1984  element->Init(this);
1985  } else {
1986  // The class is known to Cling (and thus is not emulated)
1987  // and we need to use the real offsets.
1988  // However we may not have a 'proper' TClass for it
1989  // (in which case IsLoaded will be false and GetImplFileLine will be -1)
1990 
1991  // First look for the data member in the current class
1992  dm = (TDataMember*) fClass->GetListOfDataMembers()->FindObject(element->GetName());
1993  if (dm && dm->IsPersistent()) {
1994  fClass->BuildRealData();
1995  streamer = 0;
1996  offset = GetDataMemberOffset(dm, streamer);
1997  element->SetOffset(offset);
1998  element->Init(this);
1999 
2000  // Treat unique pointers and std arrays
2001  dmType = dm->GetTypeName();
2002  dmIsPtr = dm->IsaPointer();
2003  Bool_t nameChanged;
2004  typeNameBuf = TClassEdit::GetNameForIO(dmType, TClassEdit::EModType::kNone, &nameChanged);
2005  if (nameChanged) {
2006  isUniquePtr = dmIsPtr = TClassEdit::IsUniquePtr(dmType);
2007  dmType = typeNameBuf.c_str();
2008  }
2009  if ((isStdArray = TClassEdit::IsStdArray(dmType))){ // We tackle the std array case
2010  TClassEdit::GetStdArrayProperties(dmType,
2011  typeNameBuf,
2012  maxIndices,
2013  ndim);
2014  dmType = typeNameBuf.c_str();
2015  dt = gROOT->GetType(dmType);
2016  }
2017 
2018  // We have a loaded class, let's make sure that if we have a collection
2019  // it is also loaded.
2020  TString dmClassName = TClassEdit::ShortType(dmType,TClassEdit::kDropStlDefault).c_str();
2021  dmClassName = dmClassName.Strip(TString::kTrailing, '*');
2022  if (dmClassName.Index("const ")==0) dmClassName.Remove(0,6);
2023  TClass *elemDm = ! (dt || dm->IsBasic()) ? TClass::GetClass(dmClassName.Data()) : 0;
2024  if (elemDm && elemDm->GetCollectionProxy()
2025  && !elemDm->IsLoaded()
2026  && elemDm->GetCollectionProxy()->GetCollectionType() != ROOT::kSTLvector) {
2027  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());
2028  offset = kMissing;
2029  element->SetOffset(kMissing);
2030  element->SetNewType(-1);
2031  }
2032  element->SetStreamer(streamer);
2033  int narr = element->GetArrayLength();
2034  if (!narr) {
2035  narr = 1;
2036  }
2037  int dsize = dm->GetUnitSize();
2038  element->SetSize(dsize*narr);
2039  } else {
2040  // We did not find it, let's look for it in the base classes via TRealData
2041  TRealData* rd = fClass->GetRealData(element->GetName());
2042  if (rd && rd->GetDataMember()) {
2043  element->SetOffset(rd->GetThisOffset());
2044  element->Init(this);
2045  dm = rd->GetDataMember();
2046  dmType = dm->GetTypeName();
2047  dmIsPtr = dm->IsaPointer();
2048  int narr = element->GetArrayLength();
2049  if (!narr) {
2050  narr = 1;
2051  }
2052  int dsize = dm->GetUnitSize();
2053  element->SetSize(dsize*narr);
2054  }
2055  }
2056  } // Class corresponding to StreamerInfo is emulated or not.
2057 
2058  // Now let's deal with Schema evolution
2059  Int_t newType = -1;
2060  TClassRef newClass;
2061 
2062  if (dm && dm->IsPersistent()) {
2063  auto theType = isStdArray ? dt : dm->GetDataType();
2064  if (theType) {
2065  Bool_t isArray = isStdArray || element->GetArrayLength() >= 1;
2066  Bool_t hasCount = element->HasCounter();
2067  // data member is a basic type
2068  if ((fClass == TObject::Class()) && !strcmp(dm->GetName(), "fBits")) {
2069  //printf("found fBits, changing dtype from %d to 15\n", dtype);
2070  newType = kBits;
2071  } else {
2072  // All the values of EDataType have the same semantic in EReadWrite
2073  newType = (EReadWrite)theType->GetType();
2074  }
2075  if ((newType == ::kChar_t) && dmIsPtr && !isArray && !hasCount) {
2076  newType = ::kCharStar;
2077  } else if (dmIsPtr) {
2078  newType += kOffsetP;
2079  } else if (isArray) {
2080  newType += kOffsetL;
2081  }
2082  }
2083  if (newType == -1) {
2084  newClass = TClass::GetClass(dmType);
2085  }
2086  } else {
2087  // Either the class is not loaded or the data member is gone
2088  if (!fClass->IsLoaded()) {
2090  if (newInfo && (newInfo != this)) {
2091  TStreamerElement* newElems = (TStreamerElement*) newInfo->GetElements()->FindObject(element->GetName());
2092  newClass = newElems ? newElems->GetClassPointer() : 0;
2093  if (newClass == 0) {
2094  newType = newElems ? newElems->GetType() : -1;
2095  if (!(newType < kObject)) {
2096  // sanity check.
2097  newType = -1;
2098  }
2099  }
2100  } else {
2101  newClass = element->GetClassPointer();
2102  if (newClass.GetClass() == 0) {
2103  newType = element->GetType();
2104  if (!(newType < kObject)) {
2105  // sanity check.
2106  newType = -1;
2107  }
2108  }
2109  }
2110  }
2111  }
2112 
2113  if (newType > 0) {
2114  // Case of a numerical type
2115  if (element->GetType() >= TStreamerInfo::kObject) {
2116  // Old type was not a numerical type.
2117  element->SetNewType(-2);
2118  } else if (element->GetType() != newType) {
2119  element->SetNewType(newType);
2120  if (gDebug > 0) {
2121  // coverity[mixed_enums] - All the values of EDataType have the same semantic in EReadWrite
2122  Info("BuildOld", "element: %s %s::%s has new type: %s/%d", element->GetTypeName(), GetName(), element->GetName(), dm ? dm->GetFullTypeName() : TDataType::GetTypeName((EDataType)newType), newType);
2123  }
2124  }
2125  } else if (newClass.GetClass()) {
2126  // Sometime BuildOld is called again.
2127  // In that case we might already have fix up the streamer element.
2128  // So we need to go back to the original information!
2129  newClass.Reset();
2130  TClass* oldClass = TClass::GetClass(TClassEdit::ShortType(element->GetTypeName(), TClassEdit::kDropTrailStar).c_str());
2131  if (oldClass == newClass.GetClass()) {
2132  // Nothing to do, also in the unique_ptr case :)
2133  } else if (ClassWasMovedToNamespace(oldClass, newClass.GetClass())) {
2134  Int_t oldv;
2135  if (0 != (oldv = ImportStreamerInfo(oldClass, newClass.GetClass()))) {
2136  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);
2137  } else {
2138  element->SetTypeName(newClass->GetName());
2139  if (gDebug > 0) {
2140  Warning("BuildOld", "element: %s::%s %s has new type %s", GetName(), element->GetTypeName(), element->GetName(), newClass->GetName());
2141  }
2142  }
2143  } else if (oldClass == TClonesArray::Class()) {
2144  if (ContainerMatchTClonesArray(newClass.GetClass())) {
2145  Int_t elemType = element->GetType();
2146  Bool_t isPrealloc = (elemType == kObjectp) || (elemType == kAnyp) || (elemType == (kObjectp + kOffsetL)) || (elemType == (kAnyp + kOffsetL));
2147  element->Update(oldClass, newClass.GetClass());
2148  TVirtualCollectionProxy *cp = newClass->GetCollectionProxy();
2149  TConvertClonesArrayToProxy *ms = new TConvertClonesArrayToProxy(cp, element->IsaPointer(), isPrealloc);
2150  element->SetStreamer(ms);
2151 
2152  // When the type is kObject, the TObject::Streamer is used instead
2153  // of the TStreamerElement's streamer. So let force the usage
2154  // of our streamer
2155  if (element->GetType() == kObject) {
2156  element->SetNewType(kAny);
2157  element->SetType(kAny);
2158  }
2159  if (gDebug > 0) {
2160  Warning("BuildOld","element: %s::%s %s has new type %s", GetName(), element->GetTypeName(), element->GetName(), newClass->GetName());
2161  }
2162  } else {
2163  element->SetNewType(-2);
2164  }
2165  } else if (oldClass && oldClass->GetCollectionProxy() && newClass->GetCollectionProxy()) {
2166  {
2167  TClass *oldFixedClass = FixCollectionV5(GetClass(),oldClass,newClass);
2168  if (oldFixedClass && oldFixedClass != oldClass) {
2169  element->Update(oldClass,oldFixedClass);
2170  oldClass = oldFixedClass;
2171  }
2172  }
2173  if (CollectionMatch(oldClass, newClass)) {
2174  Int_t oldkind = oldClass->GetCollectionType();
2175  Int_t newkind = newClass->GetCollectionType();
2176 
2177  if ( (oldkind==ROOT::kSTLmap || oldkind==ROOT::kSTLmultimap) &&
2178  (newkind!=ROOT::kSTLmap && newkind!=ROOT::kSTLmultimap) ) {
2179 
2180  Int_t elemType = element->GetType();
2181  Bool_t isPrealloc = (elemType == kObjectp) || (elemType == kAnyp) || (elemType == (kObjectp + kOffsetL)) || (elemType == (kAnyp + kOffsetL));
2182 
2183  TClassStreamer *streamer2 = newClass->GetStreamer();
2184  if (streamer2) {
2185  TConvertMapToProxy *ms = new TConvertMapToProxy(streamer2, element->IsaPointer(), isPrealloc);
2186  if (ms && ms->IsValid()) {
2187  element->SetStreamer(ms);
2188  switch( element->GetType() ) {
2189  //case TStreamerInfo::kSTLvarp: // Variable size array of STL containers.
2190  case TStreamerInfo::kSTLp: // Pointer to container with no virtual table (stl) and no comment
2191  case TStreamerInfo::kSTLp + TStreamerInfo::kOffsetL: // array of pointers to container with no virtual table (stl) and no comment
2192  element->SetNewType(-2);
2193  break;
2194  case TStreamerInfo::kSTL: // container with no virtual table (stl) and no comment
2195  case TStreamerInfo::kSTL + TStreamerInfo::kOffsetL: // array of containers with no virtual table (stl) and no comment
2196  break;
2197  }
2198  } else {
2199  delete ms;
2200  }
2201  }
2202  element->Update(oldClass, newClass.GetClass());
2203 
2204  } else if ( (newkind==ROOT::kSTLmap || newkind==ROOT::kSTLmultimap) &&
2205  (oldkind!=ROOT::kSTLmap && oldkind!=ROOT::kSTLmultimap) ) {
2206  element->SetNewType(-2);
2207  } else {
2208  element->Update(oldClass, newClass.GetClass());
2209  }
2210  // Is this needed ? : element->SetSTLtype(newelement->GetSTLtype());
2211  if (gDebug > 0) {
2212  Warning("BuildOld","element: %s::%s %s has new type %s", GetName(), element->GetTypeName(), element->GetName(), newClass->GetName());
2213  }
2214  } else if (CollectionMatchFloat16(oldClass,newClass)) {
2215  // Actually nothing to do, since both are the same collection of double in memory.
2216  } else if (CollectionMatchDouble32(oldClass,newClass)) {
2217  // Actually nothing to do, since both are the same collection of double in memory.
2218  } else if (CollectionMatchLong64(oldClass,newClass)) {
2219  // Not much to do since both are the same collection of 8 bits entities on file.
2220  element->Update(oldClass, newClass.GetClass());
2221  } else if (CollectionMatchULong64(oldClass,newClass)) {
2222  // Not much to do since both are the same collection of 8 bits unsigned entities on file
2223  element->Update(oldClass, newClass.GetClass());
2224  } else if (newClass->GetSchemaRules()->HasRuleWithSourceClass( oldClass->GetName() )) {
2225  //------------------------------------------------------------------------
2226  // We can convert one type to another (at least for some of the versions).
2227  /////////////////////////////////////////////////////////////////
2228 
2229  element->SetNewClass( newClass );
2230  } else {
2231  element->SetNewType(-2);
2232  }
2233 
2234  } else if(oldClass &&
2235  newClass.GetClass() &&
2236  newClass->GetSchemaRules() &&
2237  newClass->GetSchemaRules()->HasRuleWithSourceClass( oldClass->GetName() ) ) {
2238  //------------------------------------------------------------------------
2239  // We can convert one type to another (at least for some of the versions).
2240  ////////////////////////////////////////////////////////////////////
2241 
2242  element->SetNewClass( newClass );
2243  } else {
2244  element->SetNewType(-2);
2245  }
2246  // Humm we still need to make sure we have the same 'type' (pointer, embedded object, array, etc..)
2247  Bool_t cannotConvert = kFALSE;
2248  if (element->GetNewType() != -2) {
2249  if (dm) {
2250  if (dmIsPtr) {
2251  if (isUniquePtr || strncmp(dm->GetTitle(),"->",2)==0) {
2252  // We are fine, nothing to do.
2253  if (newClass->IsTObject()) {
2254  newType = kObjectp;
2255  } else if (newClass->GetCollectionProxy()) {
2256  newType = kSTLp;
2257  } else {
2258  newType = kAnyp;
2259  }
2260  } else {
2261  if (TClass::GetClass(dm->GetTypeName())->IsTObject()) {
2262  newType = kObjectP;
2263  } else if (newClass->GetCollectionProxy()) {
2264  newType = kSTLp;
2265  } else {
2266  newType = kAnyP;
2267  }
2268  }
2269  } else {
2270  if (newClass->GetCollectionProxy()) {
2271  newType = kSTL;
2272  } else if (newClass == TString::Class()) {
2273  newType = kTString;
2274  } else if (newClass == TObject::Class()) {
2275  newType = kTObject;
2276  } else if (newClass == TNamed::Class()) {
2277  newType = kTNamed;
2278  } else if (newClass->IsTObject()) {
2279  newType = kObject;
2280  } else {
2281  newType = kAny;
2282  }
2283  }
2284  if ((!dmIsPtr || newType==kSTLp) && (isStdArray ? ndim : dm->GetArrayDim()) > 0) {
2285  newType += kOffsetL;
2286  }
2287  } else if (!fClass->IsLoaded()) {
2289  if (newInfo && (newInfo != this)) {
2290  TStreamerElement* newElems = (TStreamerElement*) newInfo->GetElements()->FindObject(element->GetName());
2291  if (newElems) {
2292  newType = newElems->GetType();
2293  }
2294  } else {
2295  newType = element->GetType();
2296  }
2297  }
2298  if (element->GetType() == kSTL
2299  || ((element->GetType() == kObject || element->GetType() == kAny || element->GetType() == kObjectp || element->GetType() == kAnyp)
2300  && oldClass == TClonesArray::Class()))
2301  {
2302  cannotConvert = (newType != kSTL && newType != kObject && newType != kAny && newType != kSTLp && newType != kObjectp && newType != kAnyp);
2303 
2304  } else if (element->GetType() == kSTLp || ((element->GetType() == kObjectP || element->GetType() == kAnyP) && oldClass == TClonesArray::Class()) )
2305  {
2306  cannotConvert = (newType != kSTL && newType != kObject && newType != kAny && newType != kSTLp && newType != kObjectP && newType != kAnyP);
2307 
2308  } else if (element->GetType() == kSTL + kOffsetL
2309  || ((element->GetType() == kObject + kOffsetL|| element->GetType() == kAny + kOffsetL|| element->GetType() == kObjectp+ kOffsetL || element->GetType() == kAnyp+ kOffsetL)
2310  && oldClass == TClonesArray::Class()))
2311  {
2312  cannotConvert = (newType != kSTL + kOffsetL && newType != kObject+ kOffsetL && newType != kAny+ kOffsetL && newType != kSTLp+ kOffsetL && newType != kObjectp+ kOffsetL && newType != kAnyp+ kOffsetL);
2313 
2314  } else if (element->GetType() == kSTLp + kOffsetL || ((element->GetType() == kObjectP+ kOffsetL || element->GetType() == kAnyP+ kOffsetL) && oldClass == TClonesArray::Class()) )
2315  {
2316  cannotConvert = (newType != kSTL+ kOffsetL && newType != kObject+ kOffsetL && newType != kAny+ kOffsetL && newType != kSTLp + kOffsetL&& newType != kObjectP+ kOffsetL && newType != kAnyP+ kOffsetL);
2317 
2318  } else if ((element->GetType() == kObjectp || element->GetType() == kAnyp
2319  || element->GetType() == kObject || element->GetType() == kAny
2320  || element->GetType() == kTObject || element->GetType() == kTNamed || element->GetType() == kTString )) {
2321  // We had Type* ... ; //-> or Type ...;
2322  // this is completely compatible with the same and with a embedded object.
2323  if (newType != -1) {
2324  if (newType == kObjectp || newType == kAnyp
2325  || newType == kObject || newType == kAny
2326  || newType == kTObject || newType == kTNamed || newType == kTString) {
2327  // We are fine, no transformation to make
2328  element->SetNewType(newType);
2329  } else {
2330  // We do not support this yet.
2331  cannotConvert = kTRUE;
2332  }
2333  } else {
2334  // We have no clue
2335  printf("%s We have no clue\n", dm->GetName());
2336  cannotConvert = kTRUE;
2337  }
2338  } else if (element->GetType() == kObjectP || element->GetType() == kAnyP) {
2339  if (newType != -1) {
2340  if (newType == kObjectP || newType == kAnyP ) {
2341  // nothing to do}
2342  } else {
2343  cannotConvert = kTRUE;
2344  }
2345  } else {
2346  // We have no clue
2347  cannotConvert = kTRUE;
2348  }
2349  }
2350  }
2351  if (cannotConvert) {
2352  element->SetNewType(-2);
2353  if (gDebug > 0) {
2354  // coverity[mixed_enums] - All the values of EDataType have the same semantic in EReadWrite
2355  Info("BuildOld", "element: %s %s::%s has new type: %s/%d", element->GetTypeName(), GetName(), element->GetName(), dm ? dm->GetFullTypeName() : TDataType::GetTypeName((EDataType)newType), newType);
2356  }
2357  }
2358  } else {
2359  element->SetNewType(-1);
2360  offset = kMissing;
2361  element->SetOffset(kMissing);
2362  }
2363 
2364  if (offset != kMissing && fClass->GetState() <= TClass::kEmulated) {
2365  // Note the initialization in this case are
2366  // delayed until __after__ the schema evolution
2367  // section, just in case the info has changed.
2368 
2369  // The class is NOT known to Cling, i.e. is emulated,
2370  // and we need to use the calculated offset.
2371 
2372  Int_t asize;
2373  if (element->GetType() == TStreamerInfo::kSTL &&
2374  strcmp(element->GetName(),"This") == 0 &&
2375  strcmp(element->GetTypeName(),GetName()) == 0 &&
2376  !fClass->GetCollectionProxy()) {
2377  // Humm .. we are missing the collection Proxy
2378  // for a proxied (custom) collection ... avoid
2379  // an infinite recursion and take a wild guess
2380  asize = sizeof(std::vector<int>);
2381  } else {
2382  // Regular case
2383  asize = element->GetSize();
2384  }
2385  // align the non-basic data types (required on alpha and IRIX!!)
2386  if ((offset % kSizeOfPtr) != 0) {
2387  offset = offset - (offset % kSizeOfPtr) + kSizeOfPtr;
2388  }
2389  element->SetOffset(offset);
2390  offset += asize;
2391  }
2392 
2393  if (!wasCompiled && rules) {
2394  if (rules.HasRuleWithSource( element->GetName(), kTRUE ) ) {
2395 
2396  if (allocClass == 0) {
2397  infoalloc = (TStreamerInfo *)Clone(TString::Format("%s@@%d",GetName(),GetOnFileClassVersion()));
2398  if (!infoalloc) {
2399  Error("BuildOld","Unable to create the StreamerInfo for %s.",TString::Format("%s@@%d",GetName(),GetOnFileClassVersion()).Data());
2400  } else {
2401  infoalloc->SetBit(kBuildOldUsed,false);
2402  infoalloc->BuildCheck();
2403  infoalloc->BuildOld();
2404  allocClass = infoalloc->GetClass();
2405  }
2406  }
2407 
2408  // Now that we are caching the unconverted element, we do not assign it to the real type even if we could have!
2409  if (element->GetNewType()>0 /* intentionally not including base class for now */
2410  && !rules.HasRuleWithTarget( element->GetName(), kTRUE ) ) {
2411 
2412  TStreamerElement *copy = (TStreamerElement*)element->Clone();
2413  R__TObjArray_InsertBefore( fElements, copy, element );
2414  next(); // move the cursor passed the insert object.
2416  element = copy;
2417 
2418  // Warning("BuildOld","%s::%s is not set from the version %d of %s (You must add a rule for it)\n",GetName(), element->GetName(), GetClassVersion(), GetName() );
2419  } else {
2420  // If the element is just cached and not repeat, we need to inject an element
2421  // to insure the writing.
2422  TStreamerElement *writecopy = (TStreamerElement*)element->Clone();
2423  R__TObjArray_InsertAfter( fElements, writecopy, element );
2424  next(); // move the cursor passed the insert object.
2425  writecopy->SetBit(TStreamerElement::kWrite);
2426  writecopy->SetNewType( writecopy->GetType() );
2427  writecopy->SetBit(TStreamerElement::kCache);
2428  writecopy->SetOffset(infoalloc ? infoalloc->GetOffset(element->GetName()) : 0);
2429  }
2430  element->SetBit(TStreamerElement::kCache);
2431  element->SetNewType( element->GetType() );
2432  element->SetOffset(infoalloc ? infoalloc->GetOffset(element->GetName()) : 0);
2433  } else if (rules.HasRuleWithTarget( element->GetName(), kTRUE ) ) {
2434  // The data member exist in the onfile StreamerInfo and there is a rule
2435  // that has the same member 'only' has a target ... so this means we are
2436  // asked to ignore the input data ...
2437  if (element->GetType() == kCounter) {
2438  // If the element is a counter, we will need its value to read
2439  // other data member, so let's do so (by not disabling it) even
2440  // if the value will be over-written by a rule.
2441  } else {
2442  element->SetOffset(kMissing);
2443  }
2444  }
2445  } else if (rules && rules.HasRuleWithTarget( element->GetName(), kTRUE ) ) {
2446  // The data member exist in the onfile StreamerInfo and there is a rule
2447  // that has the same member 'only' has a target ... so this means we are
2448  // asked to ignore the input data ...
2449  if (element->GetType() == kCounter) {
2450  // If the element is a counter, we will need its value to read
2451  // other data member, so let's do so (by not disabling it) even
2452  // if the value will be over-written by a rule.
2453  } else {
2454  element->SetOffset(kMissing);
2455  }
2456  }
2457 
2458  if (element->GetNewType() == -2) {
2459  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") );
2460  }
2461  }
2462 
2463  // If we get here, this means that there no data member after the last base class
2464  // (or no base class at all).
2465  if (shouldHaveInfoLoc && fNVirtualInfoLoc==0) {
2466  fNVirtualInfoLoc = 1;
2467  fVirtualInfoLoc = new ULong_t[1]; // To allow for a single delete statement.
2468  fVirtualInfoLoc[0] = offset;
2469  offset += sizeof(TStreamerInfo*);
2470  }
2471 
2472  // change order , move "bazes" to the end. Workaround old bug
2473  if ((fOldVersion <= 2) && nBaze) {
2474  SetBit(kRecovered);
2475  TObjArray& arr = *fElements;
2476  TObjArray tai(nBaze);
2477  int narr = arr.GetLast() + 1;
2478  int iel;
2479  int jel = 0;
2480  int kel = 0;
2481  for (iel = 0; iel < narr; ++iel) {
2482  element = (TStreamerElement*) arr[iel];
2483  if (element->IsBase() && (element->IsA() != TStreamerBase::Class())) {
2484  tai[kel++] = element;
2485  } else {
2486  arr[jel++] = element;
2487  }
2488  }
2489  for (kel = 0; jel < narr;) {
2490  arr[jel++] = tai[kel++];
2491  }
2492  }
2493 
2494  // Now add artificial TStreamerElement (i.e. rules that creates new members or set transient members).
2495  if (!wasCompiled) InsertArtificialElements(rules);
2496 
2497  if (!wasCompiled && allocClass) {
2498 
2499  TStreamerElement *el = new TStreamerArtificial("@@alloc","", 0, TStreamerInfo::kCacheNew, allocClass->GetName());
2500  R__TObjArray_InsertAt( fElements, el, 0 );
2501 
2502  el = new TStreamerArtificial("@@dealloc","", 0, TStreamerInfo::kCacheDelete, allocClass->GetName());
2503  fElements->Add( el );
2504  }
2505 
2506  Compile();
2507 }
2508 
2509 ////////////////////////////////////////////////////////////////////////////////
2510 /// If opt contains 'built', reset this StreamerInfo as if Build or BuildOld
2511 /// was never called on it (useful to force their re-running).
2512 
2514 {
2515  TString opt = option;
2516  opt.ToLower();
2517 
2518  if (opt.Contains("build")) {
2520 
2521  delete [] fComp; fComp = 0;
2522  delete [] fCompFull; fCompFull= 0;
2523  delete [] fCompOpt; fCompOpt = 0;
2524  fNdata = 0;
2525  fNfulldata = 0;
2526  fNslots= 0;
2527  fSize = 0;
2528  ResetIsCompiled();
2530 
2537  }
2538 }
2539 
2540 namespace {
2541  // TMemberInfo
2542  // Local helper class to be able to compare data member represented by
2543  // 2 distinct TStreamerInfos
2544  class TMemberInfo {
2545  public:
2546  TClass *fParent;
2547  TString fName;
2548  TString fClassName;
2549  TString fComment;
2550  Int_t fDataType;
2551 
2552  TMemberInfo(TClass *parent) : fParent(parent) {};
2553 
2554  void SetDataType(Int_t datatype) {
2555  fDataType = datatype;
2556  }
2557 
2558  void SetName(const char *name) {
2559  fName = name;
2560  }
2561  void SetClassName(const char *name) {
2562  fClassName = TClassEdit::ResolveTypedef(TClassEdit::ShortType( name, TClassEdit::kDropStlDefault | TClassEdit::kDropStd ).c_str(),kTRUE);
2563  }
2564  void SetComment(const char *title) {
2565  const char *left = strstr(title,"[");
2566  if (left) {
2567  const char *right = strstr(left,"]");
2568  if (right) {
2569  ++left;
2570  fComment.Append(left,right-left);
2571  }
2572  }
2573  }
2574  void Clear() {
2575  fName.Clear();
2576  fClassName.Clear();
2577  fComment.Clear();
2578  }
2579  /* Hide this not yet used implementation to suppress warnings message
2580  from icc 11
2581  Bool_t operator==(const TMemberInfo &other) {
2582  return fName==other.fName
2583  && fClassName == other.fClassName
2584  && fComment == other.fComment;
2585  }
2586  */
2587  Bool_t operator!=(const TMemberInfo &other) {
2588  if (fName != other.fName) return kTRUE;
2589  if (fDataType < TStreamerInfo::kObject) {
2590  // For simple type, let compare the data type
2591  if (fDataType != other.fDataType) {
2592  if ( (fDataType == 4 && other.fDataType == 16)
2593  || (fDataType == 16 && other.fDataType == 4) ) {
2594  // long and 'long long' have the same file format
2595  } else if ( (fDataType == 14 && other.fDataType == 17)
2596  || (fDataType == 17 && other.fDataType == 14) ) {
2597  // unsigned long and 'unsigned long long' have the same file format
2598  } else if ( (fDataType == 3 && other.fDataType == 6)
2599  ||(fDataType == 6 && other.fDataType == 3) ){
2600  // Int_t and kCounter. As the switch from Int_t (3) to
2601  // kCounter (6) might be triggered by a derived class using
2602  // the field as an array size, the class itself has no
2603  // control on what the field type really use.
2604  } else {
2605  return kTRUE;
2606  }
2607  }
2608  } else if (fClassName != other.fClassName) {
2609  if ( (fClassName == "long" && (other.fClassName == "long long" || other.fClassName == "Long64_t"))
2610  || ( (fClassName == "long long" || fClassName == "Long64_t") && other.fClassName == "long") ) {
2611  // This is okay both have the same on file format.
2612  } else if ( (fClassName == "unsigned long" && (other.fClassName == "unsigned long long" || other.fClassName == "ULong64_t"))
2613  || ( (fClassName == "unsigned long long" || fClassName == "ULong64_t") && other.fClassName == "unsigned long") ) {
2614  // This is okay both have the same on file format.
2615  } else if (TClassEdit::IsSTLCont(fClassName)) {
2616  TString name = TClassEdit::ShortType( fClassName, TClassEdit::kDropStlDefault );
2617  TString othername = TClassEdit::ShortType( other.fClassName, TClassEdit::kDropStlDefault );
2618  if (name != othername) {
2619  TClass *cl = TClass::GetClass(name);
2620  TClass *otherCl = TClass::GetClass(othername);
2621  if (!CollectionMatch(cl,otherCl)) {
2622  TClass *oldFixedClass = FixCollectionV5(fParent,cl,otherCl);
2623  if (!oldFixedClass || !CollectionMatch(oldFixedClass,otherCl)) {
2624  return kTRUE;
2625  }
2626  }
2627  }
2628  } else {
2629  return kTRUE;
2630  }
2631  }
2632  return fComment != other.fComment;
2633  }
2634  };
2635 }
2636 
2637 ////////////////////////////////////////////////////////////////////////////////
2638 /// Emulated a call ShowMembers() on the obj of this class type, passing insp and parent.
2639 
2640 void TStreamerInfo::CallShowMembers(const void* obj, TMemberInspector &insp, Bool_t isTransient) const
2641 {
2642  TIter next(fElements);
2643  TStreamerElement* element = (TStreamerElement*) next();
2644 
2645  TString elementName;
2646 
2647  for (; element; element = (TStreamerElement*) next()) {
2648 
2649  // Skip elements which have not been allocated memory.
2650  if (element->GetOffset() == kMissing) {
2651  continue;
2652  }
2653 
2654  char* eaddr = ((char*)obj) + element->GetOffset();
2655 
2656  if (element->IsBase()) {
2657  // Nothing to do this round.
2658  } else if (element->IsaPointer()) {
2659  elementName.Form("*%s",element->GetFullName());
2660  insp.Inspect(fClass, insp.GetParent(), elementName.Data(), eaddr, isTransient);
2661  } else {
2662  insp.Inspect(fClass, insp.GetParent(), element->GetFullName(), eaddr, isTransient);
2663  Int_t etype = element->GetType();
2664  switch(etype) {
2665  case kObject:
2666  case kAny:
2667  case kTObject:
2668  case kTString:
2669  case kTNamed:
2670  case kSTL:
2671  {
2672  TClass *ecl = element->GetClassPointer();
2673  if (ecl && (fClass!=ecl /* This happens 'artificially for stl container see the use of "This" */)) {
2674  insp.InspectMember(ecl, eaddr, TString(element->GetName()) + ".", isTransient);
2675  }
2676  break;
2677  }
2678  } // switch(etype)
2679  } // if IsaPointer()
2680  } // Loop over elements
2681 
2682  // And now do the base classes
2683  next.Reset();
2684  element = (TStreamerElement*) next();
2685  for (; element; element = (TStreamerElement*) next()) {
2686  if (element->IsBase()) {
2687  // Skip elements which have not been allocated memory.
2688  if (element->GetOffset() == kMissing) {
2689  continue;
2690  }
2691 
2692  char* eaddr = ((char*)obj) + element->GetOffset();
2693 
2694  TClass *ecl = element->GetClassPointer();
2695  if (ecl) {
2696  ecl->CallShowMembers(eaddr, insp, isTransient);
2697  }
2698  } // If is a abse
2699  } // Loop over elements
2700 }
2701 
2702 ////////////////////////////////////////////////////////////////////////////////
2703 /// Make a clone of an object using the Streamer facility.
2704 /// If newname is specified, this will be the name of the new object.
2705 
2706 TObject *TStreamerInfo::Clone(const char *newname) const
2707 {
2708  TStreamerInfo *newinfo = (TStreamerInfo*)TNamed::Clone(newname);
2709  if (newname && newname[0] && fName != newname) {
2710  TObjArray *newelems = newinfo->GetElements();
2711  Int_t ndata = newelems->GetEntries();
2712  for(Int_t i = 0; i < ndata; ++i) {
2713  TObject *element = newelems->UncheckedAt(i);
2714  if (element->IsA() == TStreamerLoop::Class()) {
2715  TStreamerLoop *eloop = (TStreamerLoop*)element;
2716  if (fName == eloop->GetCountClass()) {
2717  eloop->SetCountClass(newname);
2718  eloop->Init();
2719  }
2720  } else if (element->IsA() == TStreamerBasicPointer::Class()) {
2721  TStreamerBasicPointer *eptr = (TStreamerBasicPointer*)element;
2722  if (fName == eptr->GetCountClass()) {
2723  eptr->SetCountClass(newname);
2724  eptr->Init();
2725  }
2726  }
2727  }
2728  }
2729  return newinfo;
2730 }
2731 
2732 ////////////////////////////////////////////////////////////////////////////////
2733 /// Return True if the current StreamerInfo in cl or info is equivalent to this TStreamerInfo.
2734 ///
2735 /// In this context 'Equivalent' means the same number of persistent data member which the same actual C++ type and
2736 /// the same name.
2737 /// If 'warn' is true, Warning message are printed to explicit the differences.
2738 /// If 'complete' is false, stop at the first error, otherwise continue until all members have been checked.
2739 
2741 {
2742  Bool_t result = kTRUE;
2743  R__ASSERT( (cl==0 || info==0) && (cl!=0 || info!=0) /* must compare to only one thing! */);
2744 
2745  TString name;
2746  TString type;
2747  TStreamerElement *el;
2748  TStreamerElement *infoel = 0;
2749 
2750  TIter next(GetElements());
2751  TIter infonext((TList*)0);
2752  TIter basenext((TList*)0);
2753  TIter membernext((TList*)0);
2754  if (info) {
2755  infonext = info->GetElements();
2756  }
2757  if (cl) {
2758  TList *tlb = cl->GetListOfBases();
2759  if (tlb) { // Loop over bases
2760  basenext = tlb;
2761  }
2762  tlb = cl->GetListOfDataMembers();
2763  if (tlb) {
2764  membernext = tlb;
2765  }
2766  }
2767 
2768  // First let's compare base classes
2769  Bool_t done = kFALSE;
2770  TString localClass;
2771  TString otherClass;
2772  while(!done) {
2773  localClass.Clear();
2774  otherClass.Clear();
2775  el = (TStreamerElement*)next();
2776  if (el && el->IsBase()) {
2777  localClass = el->GetName();
2778  } else {
2779  el = 0;
2780  }
2781  if (cl) {
2782  TBaseClass *tbc = (TBaseClass*)basenext();
2783  if (tbc) {
2784  otherClass = tbc->GetName();
2785  } else if (el==0) {
2786  done = kTRUE;
2787  break;
2788  }
2789  } else {
2790  infoel = (TStreamerElement*)infonext();
2791  if (infoel && infoel->IsBase()) {
2792  otherClass = infoel->GetName();
2793  } else if (el==0) {
2794  done = kTRUE;
2795  break;
2796  }
2797  }
2798  if (TClassEdit::IsSTLCont(localClass)) {
2799  localClass = TClassEdit::ShortType( localClass, TClassEdit::kDropStlDefault );
2800  otherClass = TClassEdit::ShortType( otherClass, TClassEdit::kDropStlDefault );
2801  }
2802  // Need to normalize the name
2803  if (localClass != otherClass) {
2804  if (warn) {
2805  if (el==0) {
2806  Warning("CompareContent",
2807  "The in-memory layout version %d for class '%s' has a base class (%s) that the on-file layout version %d does not have.",
2808  GetClassVersion(), GetName(), otherClass.Data(), GetClassVersion());
2809  } else if (otherClass.Length()==0) {
2810  Warning("CompareContent",
2811  "The on-file layout version %d for class '%s' has a base class (%s) that the in-memory layout version %d does not have",
2812  GetClassVersion(), GetName(), localClass.Data(), GetClassVersion());
2813  } else {
2814  Warning("CompareContent",
2815  "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'",
2816  GetClassVersion(), GetClassVersion(), GetName(), localClass.Data(), otherClass.Data());
2817  }
2818  }
2819  if (!complete) return kFALSE;
2820  result = result && kFALSE;
2821  }
2822  if (cl) {
2823  TStreamerBase *localBase = dynamic_cast<TStreamerBase*>(el);
2824  if (!localBase) continue;
2825  // We already have localBaseClass == otherBaseClass
2826  TClass *otherBaseClass = localBase->GetClassPointer();
2827  if (!otherBaseClass) continue;
2828  if (otherBaseClass->IsVersioned() && localBase->GetBaseVersion() != otherBaseClass->GetClassVersion()) {
2829  TString msg;
2830  msg.Form(" The StreamerInfo of class %s read from %s%s\n"
2831  " has the same version (=%d) as the active class but a different checksum.\n"
2832  " You should update the version to ClassDef(%s,%d).\n"
2833  " The objects on this file might not be readable because:\n"
2834  " 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).",
2835  GetName(), file ? "file " : "", file ? file->GetName() : "", fClassVersion, GetName(), fClassVersion + 1,
2836  GetClassVersion(), GetName(), otherClass.Data(), otherBaseClass->GetClassVersion(),
2837  GetClassVersion(), localBase->GetBaseVersion(), localClass.Data());
2838  TStreamerBase *otherBase = (TStreamerBase*)cl->GetStreamerInfo()->GetElements()->FindObject(otherClass);
2839  otherBase->SetErrorMessage(msg);
2840 
2841  } else if (!otherBaseClass->IsVersioned() && localBase->GetBaseCheckSum() != otherBaseClass->GetCheckSum()) {
2842  TVirtualStreamerInfo *localBaseInfo = otherBaseClass->FindStreamerInfo(localBase->GetBaseCheckSum());
2843  if (!localBaseInfo) {
2844  // We are likely in the situation where the base class comes after the derived
2845  // class in the TFile's list of StreamerInfo, so it has not yet been loaded,
2846  // let's see if it is there.
2847  const TList *list = file->GetStreamerInfoCache();
2848  localBaseInfo = list ? (TStreamerInfo*)list->FindObject(localBase->GetName()) : 0;
2849  }
2850  if (!localBaseInfo) {
2851  TString msg;
2852  msg.Form(" The StreamerInfo of the base class %s (of class %s) read from %s%s\n"
2853  " refers to a checksum (%x) that can not be found neither in memory nor in the file.\n",
2854  otherBaseClass->GetName(), localClass.Data(),
2855  file ? "file " : "", file ? file->GetName() : "",
2856  localBase->GetBaseCheckSum()
2857  );
2858  TStreamerBase *otherBase = (TStreamerBase*)cl->GetStreamerInfo()->GetElements()->FindObject(otherClass);
2859  otherBase->SetErrorMessage(msg);
2860  continue;
2861  }
2862  if (localBaseInfo->CompareContent(otherBaseClass,0,kFALSE,kFALSE,file) ) {
2863  // They are equivalent, no problem.
2864  continue;
2865  }
2866  TString msg;
2867  msg.Form(" The StreamerInfo of class %s read from %s%s\n"
2868  " has the same version (=%d) as the active class but a different checksum.\n"
2869  " You should update the version to ClassDef(%s,%d).\n"
2870  " The objects on this file might not be readable because:\n"
2871  " 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).",
2872  GetName(), file ? "file " : "", file ? file->GetName() : "", fClassVersion, GetName(), fClassVersion + 1,
2873  GetClassVersion(), GetName(), otherClass.Data(), otherBaseClass->GetCheckSum(),
2874  GetClassVersion(), localBase->GetBaseCheckSum(), localClass.Data());
2875  TStreamerBase *otherBase = (TStreamerBase*)cl->GetStreamerInfo()->GetElements()->FindObject(otherClass);
2876  otherBase->SetErrorMessage(msg);
2877  }
2878  } else {
2879  TStreamerBase *localBase = dynamic_cast<TStreamerBase*>(el);
2880  TStreamerBase *otherBase = dynamic_cast<TStreamerBase*>(infoel);
2881  if (!localBase || !otherBase) continue;
2882 
2883  // We already have localBaseClass == otherBaseClass
2884  TClass *otherBaseClass = localBase->GetClassPointer();
2885  if (otherBaseClass->IsVersioned() && localBase->GetBaseVersion() != otherBase->GetBaseVersion()) {
2886  TString msg;
2887  msg.Form(" The StreamerInfo of class %s read from %s%s\n"
2888  " has the same version (=%d) as the active class but a different checksum.\n"
2889  " You should update the version to ClassDef(%s,%d).\n"
2890  " The objects on this file might not be readable because:\n"
2891  " 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).",
2892  GetName(), file ? "file " : "", file ? file->GetName() : "", fClassVersion, GetName(), fClassVersion + 1,
2893  GetClassVersion(), GetName(), otherClass.Data(), otherBase->GetBaseVersion(),
2894  GetClassVersion(), localBase->GetBaseVersion(), localClass.Data());
2895  otherBase->SetErrorMessage(msg);
2896 
2897  } else if (!otherBaseClass->IsVersioned() && localBase->GetBaseCheckSum() != otherBase->GetBaseCheckSum())
2898  {
2899  TVirtualStreamerInfo *localBaseInfo = otherBaseClass->FindStreamerInfo(localBase->GetBaseCheckSum());
2900  TVirtualStreamerInfo *otherBaseInfo = otherBaseClass->FindStreamerInfo(otherBase->GetBaseCheckSum());
2901  if (localBaseInfo == otherBaseInfo ||
2902  localBaseInfo->CompareContent(0,otherBaseInfo,kFALSE,kFALSE,file) ) {
2903  // They are equivalent, no problem.
2904  continue;
2905  }
2906  TString msg;
2907  msg.Form(" The StreamerInfo of class %s read from %s%s\n"
2908  " has the same version (=%d) as the active class but a different checksum.\n"
2909  " You should update the version to ClassDef(%s,%d).\n"
2910  " The objects on this file might not be readable because:\n"
2911  " 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).",
2912  GetName(), file ? "file " : "", file ? file->GetName() : "", fClassVersion, GetName(), fClassVersion + 1,
2913  GetClassVersion(), GetName(), otherClass.Data(), otherBase->GetBaseCheckSum(),
2914  GetClassVersion(), localBase->GetBaseCheckSum(), localClass.Data());
2915  otherBase->SetErrorMessage(msg);
2916  }
2917  }
2918  }
2919  if (!result && !complete) {
2920  return result;
2921  }
2922  // Next the datamembers
2923  done = kFALSE;
2924  next.Reset();
2925  infonext.Reset();
2926 
2927  TMemberInfo local(GetClass());
2928  TMemberInfo other(cl ? cl : info->GetClass());
2929  UInt_t idx = 0;
2930  while(!done) {
2931  local.Clear();
2932  other.Clear();
2933  el = (TStreamerElement*)next();
2934  while (el && (el->IsBase() || el->IsA() == TStreamerArtificial::Class())) {
2935  el = (TStreamerElement*)next();
2936  ++idx;
2937  }
2938  if (el) {
2939  local.SetName( el->GetName() );
2940  local.SetClassName( el->GetTypeName() );
2941  local.SetComment( el->GetTitle() );
2942  local.SetDataType( el->GetType() );
2943  }
2944  if (cl) {
2945  TDataMember *tdm = (TDataMember*)membernext();
2946  while(tdm && ( (!tdm->IsPersistent()) || (tdm->Property()&kIsStatic) || (el && local.fName != tdm->GetName()) )) {
2947  tdm = (TDataMember*)membernext();
2948  }
2949  if (tdm) {
2950  other.SetName( tdm->GetName() );
2951  other.SetClassName( tdm->GetTrueTypeName() );
2952  other.SetComment( tdm->GetTitle() );
2953  if (tdm->GetDataType()) {
2954  // Need to update the type for arrays.
2955  if (tdm->IsaPointer()) {
2956  if (tdm->GetDataType()->GetType() == TVirtualStreamerInfo::kChar && !tdm->GetArrayDim() && tdm->GetArrayIndex()[0]==0) {
2957  other.SetDataType( TVirtualStreamerInfo::kCharStar );
2958  } else {
2959  other.SetDataType( tdm->GetDataType()->GetType() + TVirtualStreamerInfo::kOffsetP);
2960  }
2961  } else {
2962  if (tdm->GetArrayDim()) {
2963  other.SetDataType( tdm->GetDataType()->GetType() + TVirtualStreamerInfo::kOffsetL);
2964  } else {
2965  other.SetDataType( tdm->GetDataType()->GetType() );
2966  }
2967  }
2968  }
2969  } else if (el==0) {
2970  done = kTRUE;
2971  break;
2972  }
2973  } else {
2974  infoel = (TStreamerElement*)infonext();
2975  while (infoel && (infoel->IsBase() || infoel->IsA() == TStreamerArtificial::Class())) {
2976  infoel = (TStreamerElement*)infonext();
2977  }
2978  if (infoel) {
2979  other.SetName( infoel->GetName() );
2980  other.SetClassName( infoel->GetTypeName() );
2981  other.SetComment( infoel->GetTitle() );
2982  other.SetDataType( infoel->GetType() );
2983  } else if (el==0) {
2984  done = kTRUE;
2985  break;
2986  }
2987  }
2988  if (local!=other) {
2989  if (warn) {
2990  if (!el) {
2991  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"
2992  " %s %s; //%s"
2994  ,other.fClassName.Data(),other.fName.Data(),other.fComment.Data());
2995 
2996  } else if (other.fName.Length()==0) {
2997  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"
2998  " %s %s; //%s"
3000  ,local.fClassName.Data(),local.fName.Data(),local.fComment.Data());
3001  } else {
3002  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"
3003  " %s %s; //%s\n"
3004  "vs\n"
3005  " %s %s; //%s"
3007  ,local.fClassName.Data(),local.fName.Data(),local.fComment.Data()
3008  ,other.fClassName.Data(),other.fName.Data(),other.fComment.Data());
3009  }
3010  }
3011  result = result && kFALSE;
3012  if (!complete) return result;
3013  }
3014  ++idx;
3015  }
3016  return result;
3017 }
3018 
3019 
3020 ////////////////////////////////////////////////////////////////////////////////
3021 /// Compute total size of all persistent elements of the class
3022 
3024 {
3026  //faster and more precise to use last element offset +size
3027  //on 64 bit machines, offset may be forced to be a multiple of 8 bytes
3028  fSize = element ? element->GetOffset() + element->GetSize() : 0;
3029  if (fNVirtualInfoLoc > 0 && (fVirtualInfoLoc[0]+sizeof(TStreamerInfo*)) >= (ULong_t)fSize) {
3030  fSize = fVirtualInfoLoc[0] + sizeof(TStreamerInfo*);
3031  }
3032 
3033  // On some platform and in some case of layout non-basic data types needs
3034  // to be aligned. So let's be on the safe side and align on the size of
3035  // the pointers. (Question: is that the right thing on x32 ABI ?)
3036  constexpr size_t kSizeOfPtr = sizeof(void*);
3037  if ((fSize % kSizeOfPtr) != 0) {
3038  fSize = fSize - (fSize % kSizeOfPtr) + kSizeOfPtr;
3039  }
3040 }
3041 
3042 ////////////////////////////////////////////////////////////////////////////////
3043 /// Recursively mark streamer infos for writing to a file.
3044 ///
3045 /// Will force this TStreamerInfo to the file and also
3046 /// all the dependencies.
3047 /// If argument force > 0 the loop on class dependencies is forced.
3048 /// This function is called when streaming a class that contains
3049 /// a null pointer. In this case, the TStreamerInfo for the class
3050 /// with the null pointer must be written to the file and also all
3051 /// the TStreamerInfo of all the classes referenced by the class.
3052 /// We must be given a file to write to.
3053 
3055 {
3056  if (!file) {
3057  return;
3058  }
3059  // Get the given file's list of streamer infos marked for writing.
3060  TArrayC* cindex = file->GetClassIndex();
3061  //the test below testing fArray[fNumber]>1 is to avoid a recursivity
3062  //problem in some cases like:
3063  // class aProblemChild: public TNamed {
3064  // aProblemChild *canBeNull;
3065  // };
3066  if ( // -- Done if already marked, and we are not forcing, or forcing is blocked.
3067  (cindex->fArray[fNumber] && !force) || // Streamer info is already marked, and not forcing, or
3068  (cindex->fArray[fNumber] > 1) // == 2 means ignore forcing to prevent infinite recursion.
3069  ) {
3070  return;
3071  }
3072  // We do not want to write streamer info to the file
3073  // for std::string.
3074  static TClassRef string_classref("string");
3075  if (fClass == string_classref) { // We are std::string.
3076  return;
3077  }
3078  // We do not want to write streamer info to the file
3079  // for STL containers.
3080  if (fClass==0) {
3081  // Build or BuildCheck has not been called yet.
3082  // Let's use another means of checking.
3083  if (fElements && fElements->GetEntries()==1 && strcmp("This",fElements->UncheckedAt(0)->GetName())==0) {
3084  // We are an STL collection.
3085  return;
3086  }
3087  } else if (fClass->GetCollectionProxy()) { // We are an STL collection.
3088  return;
3089  }
3090  // Mark ourselves for output, and block
3091  // forcing to prevent infinite recursion.
3092  cindex->fArray[fNumber] = 2;
3093  // Signal the file that the marked streamer info list has changed.
3094  cindex->fArray[0] = 1;
3095  // Recursively mark the streamer infos for
3096  // all of our elements.
3097  TIter next(fElements);
3098  TStreamerElement* element = (TStreamerElement*) next();
3099  for (; element; element = (TStreamerElement*) next()) {
3100  if (element->IsTransient()) continue;
3101  TClass* cl = element->GetClassPointer();
3102  if (cl) {
3103  TVirtualStreamerInfo* si = 0;
3104  if (cl->Property() & kIsAbstract) {
3105  // If the class of the element is abstract, register the
3106  // TStreamerInfo only if it has already been built.
3107  // Otherwise call cl->GetStreamerInfo() would generate an
3108  // incorrect StreamerInfo.
3109  si = cl->GetCurrentStreamerInfo();
3110  } else {
3111  si = cl->GetStreamerInfo();
3112  }
3113  if (si) {
3114  si->ForceWriteInfo(file, force);
3115  }
3116  }
3117  }
3118 }
3119 
3120 ////////////////////////////////////////////////////////////////////////////////
3121 /// Assuming that obj points to (the part of) an object that is of the
3122 /// type described by this streamerInfo, return the actual type of the
3123 /// object (i.e. the type described by this streamerInfo is a base class
3124 /// of the actual type of the object.
3125 /// This routine should only be called if the class described by this
3126 /// StreamerInfo is 'emulated'.
3127 
3128 TClass *TStreamerInfo::GetActualClass(const void *obj) const
3129 {
3130  R__ASSERT(!fClass->IsLoaded());
3131 
3132  if (fNVirtualInfoLoc != 0) {
3133  TStreamerInfo *allocator = *(TStreamerInfo**)( (const char*)obj + fVirtualInfoLoc[0] );
3134  if (allocator) return allocator->GetClass();
3135  }
3136  return (TClass*)fClass;
3137 }
3138 
3139 ////////////////////////////////////////////////////////////////////////////////
3140 /// Return true if the checksum passed as argument is one of the checksum
3141 /// value produced by the older checksum calculation algorithm.
3142 
3144 {
3145  for(UInt_t i = 1; i < TClass::kLatestCheckSum; ++i) {
3146  if ( checksum == GetCheckSum( (TClass::ECheckSum) i) ) return kTRUE;
3147  }
3148  return kFALSE;
3149 }
3150 
3151 ////////////////////////////////////////////////////////////////////////////////
3152 /// Recalculate the checksum of this TStreamerInfo based on its code.
3153 ///
3154 /// The class ckecksum is used by the automatic schema evolution algorithm
3155 /// to uniquely identify a class version.
3156 /// The check sum is built from the names/types of base classes and
3157 /// data members.
3158 /// The valid range of code is determined by ECheckSum.
3159 /// - kNoEnum: data members of type enum are not counted in the checksum
3160 /// - kNoRange: return the checksum of data members and base classes, not including the ranges and array size found in comments.
3161 /// - kWithTypeDef: use the sugared type name in the calculation.
3162 ///
3163 /// This is needed for backward compatibility.
3164 /// ### WARNING
3165 /// This function must be kept in sync with TClass::GetCheckSum.
3166 /// They are both used to handle backward compatibility and should both return the same values.
3167 /// TStreamerInfo uses the information in TStreamerElement while TClass uses the information
3168 /// from TClass::GetListOfBases and TClass::GetListOfDataMembers.
3169 /// Original algorithm from Victor Perevovchikov (perev@bnl.gov).
3170 
3172 {
3173  // kCurrentCheckSum (0) should be kept for backward compatibility, to be
3174  // able to use the inequality checks, we need to set the code to the largest
3175  // value.
3177 
3178  UInt_t id = 0;
3179 
3180  int il;
3181  TString name = GetName();
3182  TString type;
3183  il = name.Length();
3184  for (int i=0; i<il; i++) id = id*3+name[i];
3185 
3186  TIter next(GetElements());
3187  TStreamerElement *el;
3188  while ( (el=(TStreamerElement*)next()) && !fClass->GetCollectionProxy()) { // loop over bases if not a proxied collection
3189  if (el->IsBase()) {
3190  name = el->GetName();
3191  il = name.Length();
3192  for (int i=0; i<il; i++) id = id*3+name[i];
3193  if (code > TClass::kNoBaseCheckSum && el->IsA() == TStreamerBase::Class()) {
3194  TStreamerBase *base = (TStreamerBase*)el;
3195  id = id*3 + base->GetBaseCheckSum();
3196  }
3197  }
3198  } /* End of Base Loop */
3199 
3200  next.Reset();
3201  while ( (el=(TStreamerElement*)next()) ) {
3202  if (el->IsBase()) continue;
3203 
3204  // humm can we tell if a TStreamerElement is an enum?
3205  // Maybe something like:
3206  Bool_t isenum = kFALSE;
3207  if ( el->GetType()==3 && gROOT->GetType(el->GetTypeName())==0) {
3208  // If the type is not an enum but a typedef to int then
3209  // el->GetTypeName() should be return 'int'
3210  isenum = kTRUE;
3211  }
3212  if ( (code > TClass::kNoEnum) && isenum) id = id*3 + 1;
3213 
3214  name = el->GetName(); il = name.Length();
3215 
3216  int i;
3217  for (i=0; i<il; i++) id = id*3+name[i];
3218 
3219  if (code == TClass::kReflex || code == TClass::kReflexNoComment) {
3220  // With TClass::kReflexV5 we do not want the Long64 in the name
3221  // nor any typedef.
3222  type = TClassEdit::ResolveTypedef(el->GetTypeName(),kTRUE);
3223 
3224  } else if (code <= TClass::kWithTypeDef) {
3225  // humm ... In the streamerInfo we only have the desugared/normalized
3226  // names, so we are unable to calculate the name with typedefs ...
3227  // except for the case of the ROOT typedef (Int_t, etc.) which are
3228  // kept by TClassEdit::ResolveTypedef(typeName) but not by TCling's
3229  // normalization ...
3230  //
3231  type = el->GetTypeName();
3232  } else {
3233  type = TClassEdit::GetLong64_Name(TClassEdit::ResolveTypedef(el->GetTypeName(),kTRUE));
3234  }
3235  if (TClassEdit::IsSTLCont(type)) {
3236  type = TClassEdit::ShortType( type, TClassEdit::kDropStlDefault | TClassEdit::kLong64 );
3237  }
3238  if (code == TClass::kReflex || code == TClass::kReflexNoComment) {
3239  type.ReplaceAll("ULong64_t","unsigned long long");
3240  type.ReplaceAll("Long64_t","long long");
3241  type.ReplaceAll("signed char","char");
3242  type.ReplaceAll("<signed char","<char");
3243  type.ReplaceAll(",signed char",",char");
3244  if (type=="signed char") type = "char";
3245  }
3246 
3247  il = type.Length();
3248  for (i=0; i<il; i++) id = id*3+type[i];
3249 
3250  int dim = el->GetArrayDim();
3251  if (dim) {
3252  for (i=0;i<dim;i++) id = id*3+el->GetMaxIndex(i);
3253  }
3254 
3255 
3256  if (code > TClass::kNoRange) {
3257  const char *left;
3258  if (code > TClass::kNoRangeCheck)
3260  else
3261  left = strstr(el->GetTitle(),"[");
3262  if (left) {
3263  const char *right = strstr(left,"]");
3264  if (right) {
3265  ++left;
3266  while (left != right) {
3267  id = id*3 + *left;
3268  ++left;
3269  }
3270  }
3271  }
3272  }
3273  }
3274  return id;
3275 }
3276 
3277 ////////////////////////////////////////////////////////////////////////////////
3278 
3279 static void R__WriteConstructorBody(FILE *file, TIter &next)
3280 {
3281  TStreamerElement *element = 0;
3282  next.Reset();
3283  while ((element = (TStreamerElement*)next())) {
3288  if(element->GetArrayLength() <= 1) {
3289  fprintf(file," %s = 0;\n",element->GetName());
3290  } else {
3291  fprintf(file," memset(%s,0,%d);\n",element->GetName(),element->GetSize());
3292  }
3293  }
3294  if (TVirtualStreamerInfo::kOffsetP <= element->GetType() && element->GetType() < TVirtualStreamerInfo::kObject ) {
3295  fprintf(file," %s = 0;\n",element->GetName());
3296  }
3297  }
3298 }
3299 
3300 ////////////////////////////////////////////////////////////////////////////////
3301 /// Write down the body of the 'move' constructor.
3302 
3303 static void R__WriteMoveConstructorBody(FILE *file, const TString &protoname, TIter &next)
3304 {
3305  TStreamerElement *element = 0;
3306  next.Reset();
3307  Bool_t atstart = kTRUE;
3308  while ((element = (TStreamerElement*)next())) {
3309  if (element->IsBase()) {
3310  if (atstart) { fprintf(file," : "); atstart = kFALSE; }
3311  else fprintf(file," , ");
3312  fprintf(file, "%s(const_cast<%s &>( rhs ))\n", element->GetName(),protoname.Data());
3313  } else {
3314  if (element->GetArrayLength() <= 1) {
3315  if (atstart) { fprintf(file," : "); atstart = kFALSE; }
3316  else fprintf(file," , ");
3317  fprintf(file, "%s(const_cast<%s &>( rhs ).%s)\n",element->GetName(),protoname.Data(),element->GetName());
3318  }
3319  }
3320  }
3321  fprintf(file,"{\n");
3322  fprintf(file," // This is NOT a copy constructor. This is actually a move constructor (for stl container's sake).\n");
3323  fprintf(file," // Use at your own risk!\n");
3324  fprintf(file," (void)rhs; // avoid warning about unused parameter\n");
3325  next.Reset();
3326  Bool_t defMod = kFALSE;
3327  while ((element = (TStreamerElement*)next())) {
3330  || element->GetType() == TVirtualStreamerInfo::kAnyPnoVT)
3331  {
3332  if (!defMod) { fprintf(file," %s &modrhs = const_cast<%s &>( rhs );\n",protoname.Data(),protoname.Data()); defMod = kTRUE; };
3333  const char *ename = element->GetName();
3334  const char *colon2 = strstr(ename,"::");
3335  if (colon2) ename = colon2+2;
3336  if(element->GetArrayLength() <= 1) {
3337  fprintf(file," modrhs.%s = 0;\n",ename);
3338  } else {
3339  fprintf(file," memset(modrhs.%s,0,%d);\n",ename,element->GetSize());
3340  }
3341  } else {
3342  const char *ename = element->GetName();
3343  if (element->GetType() == kCharStar) {
3344  if (!defMod) {
3345  fprintf(file," %s &modrhs = const_cast<%s &>( rhs );\n",protoname.Data(),protoname.Data()); defMod = kTRUE;
3346  };
3347  fprintf(file," modrhs.%s = 0;\n",ename);
3348  } else if (TVirtualStreamerInfo::kOffsetP <= element->GetType() && element->GetType() < TVirtualStreamerInfo::kObject ) {
3349  if (!defMod) {
3350  fprintf(file," %s &modrhs = const_cast<%s &>( rhs );\n",protoname.Data(),protoname.Data()); defMod = kTRUE;
3351  };
3352  fprintf(file," modrhs.%s = 0;\n",ename);
3353  } else if (element->GetArrayLength() > 1) {
3354  // FIXME: Need to add support for variable length array.
3355  if (element->GetArrayDim() == 1) {
3356  fprintf(file," for (Int_t i=0;i<%d;i++) %s[i] = rhs.%s[i];\n",element->GetArrayLength(),ename,ename);
3357  } else if (element->GetArrayDim() >= 2) {
3358  fprintf(file," for (Int_t i=0;i<%d;i++) (&(%s",element->GetArrayLength(),ename);
3359  for (Int_t d = 0; d < element->GetArrayDim(); ++d) {
3360  fprintf(file,"[0]");
3361  }
3362  fprintf(file,"))[i] = (&(rhs.%s",ename);
3363  for (Int_t d = 0; d < element->GetArrayDim(); ++d) {
3364  fprintf(file,"[0]");
3365  }
3366  fprintf(file,"))[i];\n");
3367  }
3368  } else if (element->GetType() == TVirtualStreamerInfo::kSTLp) {
3369  if (!defMod) { fprintf(file," %s &modrhs = const_cast<%s &>( rhs );\n",protoname.Data(),protoname.Data()); defMod = kTRUE; };
3370  fprintf(file," modrhs.%s = 0;\n",ename);
3371  } else if (element->GetType() == TVirtualStreamerInfo::kSTL) {
3372  if (!defMod) {
3373  fprintf(file," %s &modrhs = const_cast<%s &>( rhs );\n",protoname.Data(),protoname.Data()); defMod = kTRUE;
3374  }
3375  TClass *cle = element->GetClassPointer();
3376  TVirtualCollectionProxy *proxy = cle ? element->GetClassPointer()->GetCollectionProxy() : 0;
3377  std::string method_name = "clear";
3378  if (!element->TestBit(TStreamerElement::kDoNotDelete) && proxy && (((TStreamerSTL*)element)->GetSTLtype() == ROOT::kSTLbitset)) {
3379  method_name = "reset";
3380  }
3381  if (element->IsBase()) {
3382  fprintf(file," modrhs.%s();\n", method_name.c_str());
3383  } else {
3384  fprintf(file," modrhs.%s.%s();\n",ename, method_name.c_str());
3385  }
3386  }
3387  }
3388  }
3389 }
3390 
3391 ////////////////////////////////////////////////////////////////////////////////
3392 
3393 static void R__WriteDestructorBody(FILE *file, TIter &next)
3394 {
3395  TStreamerElement *element = 0;
3396  next.Reset();
3397  while ((element = (TStreamerElement*)next())) {
3400  || element->GetType() == TVirtualStreamerInfo::kAnyPnoVT)
3401  {
3402  const char *ename = element->GetName();
3403  const char *colon2 = strstr(ename,"::");
3404  if (colon2) ename = colon2+2;
3405  if (element->TestBit(TStreamerElement::kDoNotDelete)) {
3406  if(element->GetArrayLength() <= 1) {
3407  fprintf(file," %s = 0;\n",ename);
3408  } else {
3409  fprintf(file," memset(%s,0,%d);\n",ename,element->GetSize());
3410  }
3411  } else {
3412  if(element->GetArrayLength() <= 1) {
3413  fprintf(file," delete %s; %s = 0;\n",ename,ename);
3414  } else {
3415  fprintf(file," for (Int_t i=0;i<%d;i++) delete %s[i]; memset(%s,0,%d);\n",element->GetArrayLength(),ename,ename,element->GetSize());
3416  }
3417  }
3418  }
3419  if (element->GetType() == TVirtualStreamerInfo::kCharStar) {
3420  const char *ename = element->GetName();
3421  if (element->TestBit(TStreamerElement::kDoNotDelete)) {
3422  fprintf(file," %s = 0;\n",ename);
3423  } else {
3424  fprintf(file," delete [] %s; %s = 0;\n",ename,ename);
3425  }
3426  }
3427  if (TVirtualStreamerInfo::kOffsetP <= element->GetType() && element->GetType() < TVirtualStreamerInfo::kObject ) {
3428  const char *ename = element->GetName();
3429  if (element->TestBit(TStreamerElement::kDoNotDelete)) {
3430  fprintf(file," %s = 0;\n",ename);
3431  } else if (element->HasCounter()) {
3432  fprintf(file," delete %s; %s = 0;\n",ename,ename);
3433  } else {
3434  fprintf(file," delete [] %s; %s = 0;\n",ename,ename);
3435  }
3436  }
3437  if (element->GetType() == TVirtualStreamerInfo::kSTL || element->GetType() == TVirtualStreamerInfo::kSTLp) {
3438  const char *ename = element->GetName();
3439  const char *prefix = "";
3440  if ( element->GetType() == TVirtualStreamerInfo::kSTLp ) {
3441  prefix = "*";
3442  } else if ( element->IsBase() ) {
3443  ename = "this";
3444  }
3445  TClass *cle = element->GetClassPointer();
3446  TVirtualCollectionProxy *proxy = cle ? element->GetClassPointer()->GetCollectionProxy() : 0;
3447  if (!element->TestBit(TStreamerElement::kDoNotDelete) && proxy) {
3448  Int_t stltype = ((TStreamerSTL*)element)->GetSTLtype();
3449 
3450  if (proxy->HasPointers()) {
3451  fprintf(file," std::for_each( (%s %s).rbegin(), (%s %s).rend(), DeleteObjectFunctor() );\n",prefix,ename,prefix,ename);
3452  //fprintf(file," %s::iterator iter;\n");
3453  //fprintf(file," %s::iterator begin = (%s %s).begin();\n");
3454  //fprintf(file," %s::iterator end (%s %s).end();\n");
3455  //fprintf(file," for( iter = begin; iter != end; ++iter) { delete *iter; }\n");
3456  } else {
3457  if (stltype == ROOT::kSTLmap || stltype == ROOT::kSTLmultimap) {
3459  std::vector<std::string> inside;
3460  int nestedLoc;
3461  TClassEdit::GetSplit(enamebasic, inside, nestedLoc, TClassEdit::kLong64);
3462  if (inside[1][inside[1].size()-1]=='*' || inside[2][inside[2].size()-1]=='*') {
3463  fprintf(file," std::for_each( (%s %s).rbegin(), (%s %s).rend(), DeleteObjectFunctor() );\n",prefix,ename,prefix,ename);
3464  }
3465  }
3466  }
3467  }
3468  if ( prefix[0] ) {
3469  fprintf(file," delete %s; %s = 0;\n",ename,ename);
3470  }
3471  }
3472  }
3473 }
3474 
3475 ////////////////////////////////////////////////////////////////////////////////
3476 /// Write the Declaration of class.
3477 
3478 void TStreamerInfo::GenerateDeclaration(FILE *fp, FILE *sfp, const TList *subClasses, Bool_t top)
3479 {
3480  if (fClassVersion == -3) {
3481  return;
3482  }
3483 
3484  Bool_t needGenericTemplate = fElements==0 || fElements->GetEntries() == 0;
3485  Bool_t isTemplate = kFALSE;
3486  const char *clname = GetName();
3487  TString template_protoname;
3488  if (strchr(clname, ':')) {
3489  // We might have a namespace in front of the classname.
3490  Int_t len = strlen(clname);
3491  const char *name = clname;
3492  UInt_t nest = 0;
3493  UInt_t pr_pos = 0;
3494  for (Int_t cur = 0; cur < len; ++cur) {
3495  switch (clname[cur]) {
3496  case '<':
3497  ++nest;
3498  pr_pos = cur;
3499  isTemplate = kTRUE;
3500  break;
3501  case '>':
3502  if (nest == 0) { cur = len; continue; } // the name is not well formed, give up.
3503  --nest;
3504  break;
3505  case ':': {
3506  if (nest == 0 && clname[cur+1] == ':') {
3507  // We have a scope
3508  isTemplate = kFALSE;
3509  name = clname + cur + 2;
3510  }
3511  break;
3512  }
3513  }
3514  }
3515  if (isTemplate) {
3516  template_protoname.Append(clname,pr_pos);
3517  }
3518  clname = name;
3519  } else {
3520  const char *where = strstr(clname, "<");
3521  isTemplate = where != 0;
3522  if (isTemplate) {
3523  template_protoname.Append(clname,where-clname);
3524  }
3525  }
3526 
3527  if (needGenericTemplate && isTemplate) {
3528  TString templateName(TMakeProject::GetHeaderName("template "+template_protoname,0));
3529  fprintf(fp, "#ifndef %s_h\n", templateName.Data());
3530  fprintf(fp, "#define %s_h\n", templateName.Data());
3531  }
3532 
3533  TString protoname;
3534  UInt_t numberOfNamespaces = TMakeProject::GenerateClassPrefix(fp, GetName(), top, protoname, 0, kFALSE, needGenericTemplate);
3535 
3536  // Generate class statement with base classes.
3537  TStreamerElement *element;
3538  TIter next(fElements);
3539  Int_t nbase = 0;
3540  while ((element = (TStreamerElement*)next())) {
3541  if (!element->IsBase()) continue;
3542  nbase++;
3543  const char *ename = element->GetName();
3544  if (nbase == 1) fprintf(fp," : public %s",ename);
3545  else fprintf(fp," , public %s",ename);
3546  }
3547  fprintf(fp," {\n");
3548 
3549  // Generate forward declaration nested classes.
3550  if (subClasses && subClasses->GetEntries()) {
3551  Bool_t needheader = true;
3552 
3553  TIter subnext(subClasses);
3554  TStreamerInfo *subinfo;
3555  Int_t len = strlen(GetName());
3556  while ((subinfo = (TStreamerInfo*)subnext())) {
3557  if (strncmp(GetName(),subinfo->GetName(),len)==0 && (subinfo->GetName()[len]==':') ) {
3558  if (subinfo->GetName()[len+1]==':' && strstr(subinfo->GetName()+len+2,":")==0) {
3559  if (needheader) {
3560  fprintf(fp,"\npublic:\n");
3561  fprintf(fp,"// Nested classes forward declaration.\n");
3562  needheader = false;
3563  }
3564  TString sub_protoname;
3565  UInt_t sub_numberOfClasses = 0;
3566  UInt_t sub_numberOfNamespaces;
3567  if (subinfo->GetClassVersion() == -3) {
3568  sub_numberOfNamespaces = TMakeProject::GenerateClassPrefix(fp, subinfo->GetName() + len+2, kFALSE, sub_protoname, &sub_numberOfClasses, 3);
3569  } else {
3570  sub_numberOfNamespaces = TMakeProject::GenerateClassPrefix(fp, subinfo->GetName() + len+2, kFALSE, sub_protoname, &sub_numberOfClasses, kFALSE);
3571  fprintf(fp, ";\n");
3572  }
3573 
3574  for (UInt_t i = 0;i < sub_numberOfClasses;++i) {
3575  fprintf(fp, "}; // end of class.\n");
3576  }
3577  if (sub_numberOfNamespaces > 0) {
3578  Error("GenerateDeclaration","Nested classes %s thought to be inside a namespace inside the class %s",subinfo->GetName(),GetName());
3579  }
3580  }
3581  }
3582  }
3583  }
3584 
3585  fprintf(fp,"\npublic:\n");
3586  fprintf(fp,"// Nested classes declaration.\n");
3587 
3588  // Generate nested classes.
3589  if (subClasses && subClasses->GetEntries()) {
3590  TIter subnext(subClasses,kIterBackward);
3591  TStreamerInfo *subinfo;
3592  Int_t len = strlen(GetName());
3593  while ((subinfo = (TStreamerInfo*)subnext())) {
3594  if (strncmp(GetName(),subinfo->GetName(),len)==0 && (subinfo->GetName()[len]==':')) {
3595  if (subinfo->GetName()[len+1]==':' && strstr(subinfo->GetName()+len+2,":")==0) {
3596  subinfo->GenerateDeclaration(fp, sfp, subClasses, kFALSE);
3597  }
3598  }
3599  }
3600  }
3601 
3602  fprintf(fp,"\npublic:\n");
3603  fprintf(fp,"// Data Members.\n");
3604 
3605  {
3606  // Generate data members.
3607  TString name(128);
3608  Int_t ltype = 12;
3609  Int_t ldata = 10;
3610  Int_t lt,ld,is;
3611  TString line;
3612  line.Resize(kMaxLen);
3613  next.Reset();
3614  while ((element = (TStreamerElement*)next())) {
3615 
3616  if (element->IsBase()) continue;
3617  const char *ename = element->GetName();
3618 
3619  name = ename;
3620  for (Int_t i=0;i < element->GetArrayDim();i++) {
3621  name += TString::Format("[%d]",element->GetMaxIndex(i));
3622  }
3623  name += ";";
3624  ld = name.Length();
3625 
3626  TString enamebasic = element->GetTypeNameBasic();
3627  if (element->IsA() == TStreamerSTL::Class()) {
3628  // If we have a map, multimap, set or multiset,
3629  // and the key is a class, we need to replace the
3630  // container by a vector since we don't have the
3631  // comparator function.
3632  Int_t stltype = ((TStreamerSTL*)element)->GetSTLtype();
3633  switch (stltype) {
3634  case ROOT::kSTLmap:
3635  case ROOT::kSTLmultimap:
3636  case ROOT::kSTLset:
3637  case ROOT::kSTLmultiset:
3638  case ROOT::kSTLunorderedset:
3639  case ROOT::kSTLunorderedmultiset:
3640  {
3641  enamebasic = TMakeProject::UpdateAssociativeToVector(enamebasic);
3642  }
3643  default:
3644  // nothing to do.
3645  break;
3646  }
3647  }
3648 
3649  lt = enamebasic.Length();
3650 
3651  line = " ";
3652  line += enamebasic;
3653  if (lt>=ltype) ltype = lt+1;
3654 
3655  for (is = 3+lt; is < (3+ltype); ++is) line += ' ';
3656 
3657  line += name;
3658  if (element->IsaPointer() && !strchr(line,'*')) line[2+ltype] = '*';
3659 
3660  if (ld>=ldata) ldata = ld+1;
3661  for (is = 3+ltype+ld; is < (3+ltype+ldata); ++is) line += ' ';
3662 
3663  line += " //";
3664  line += element->GetTitle();
3665  fprintf(fp,"%s\n",line.Data());
3666  }
3667  }
3668  if (needGenericTemplate && isTemplate) {
3669  // Generate default functions, ClassDef and trailer.
3670  fprintf(fp,"\n %s() {\n",protoname.Data());
3671  R__WriteConstructorBody(fp,next);
3672  fprintf(fp," }\n");
3673  fprintf(fp," %s(const %s & rhs )\n",protoname.Data(),protoname.Data());
3674  R__WriteMoveConstructorBody(fp,protoname,next);
3675  fprintf(fp," }\n");
3676  fprintf(fp," virtual ~%s() {\n",protoname.Data());
3677  R__WriteDestructorBody(fp,next);
3678  fprintf(fp," }\n\n");
3679 
3680  } else {
3681  // Generate default functions, ClassDef and trailer.
3682  fprintf(fp,"\n %s();\n",protoname.Data());
3683  fprintf(fp," %s(const %s & );\n",protoname.Data(),protoname.Data());
3684  fprintf(fp," virtual ~%s();\n\n",protoname.Data());
3685 
3686  // Add the implementations to the source.cxx file.
3688  fprintf(sfp,"#ifndef %s_cxx\n",guard.Data());
3689  fprintf(sfp,"#define %s_cxx\n",guard.Data());
3690  fprintf(sfp,"%s::%s() {\n",GetName(),protoname.Data());
3691  R__WriteConstructorBody(sfp,next);
3692  fprintf(sfp,"}\n");
3693 
3694  fprintf(sfp,"%s::%s(const %s & rhs)\n",GetName(),protoname.Data(),protoname.Data());
3695  R__WriteMoveConstructorBody(sfp,protoname,next);
3696  fprintf(sfp,"}\n");
3697 
3698  fprintf(sfp,"%s::~%s() {\n",GetName(),protoname.Data());
3699  R__WriteDestructorBody(sfp,next);
3700  fprintf(sfp,"}\n");
3701  fprintf(sfp,"#endif // %s_cxx\n\n",guard.Data());
3702  }
3703 
3704  TClass *cl = gROOT->GetClass(GetName());
3705  if (fClassVersion > 1 || (cl && cl->IsTObject()) ) {
3706  // add 1 to class version in case we didn't manage reproduce the class layout to 100%.
3707  if (fClassVersion == 0) {
3708  // If the class was declared 'transient', keep it that way.
3709  fprintf(fp," ClassDef(%s,%d); // Generated by MakeProject.\n",protoname.Data(),0);
3710  } else {
3711  fprintf(fp," ClassDef(%s,%d); // Generated by MakeProject.\n",protoname.Data(),fClassVersion + 1);
3712  }
3713  }
3714  fprintf(fp,"};\n");
3715 
3716  for(UInt_t i=0;i<numberOfNamespaces;++i) {
3717  fprintf(fp,"} // namespace\n");
3718  }
3719 
3720  if (needGenericTemplate && isTemplate) {
3721  fprintf(fp,"#endif // generic template declaration\n");
3722  }
3723 }
3724 
3725 ////////////////////////////////////////////////////////////////////////////////
3726 /// Add to the header file, the \#include need for this class.
3727 
3728 UInt_t TStreamerInfo::GenerateIncludes(FILE *fp, char *inclist, const TList *extrainfos)
3729 {
3730  if (inclist[0]==0) {
3731  // Always have this include for ClassDef.
3732  TMakeProject::AddInclude( fp, "Rtypes.h", kFALSE, inclist);
3733  }
3734  UInt_t ninc = 0;
3735 
3736  const char *clname = GetName();
3737  if (strchr(clname,'<')) {
3738  // This is a template, we need to check the template parameter.
3739  ninc += TMakeProject::GenerateIncludeForTemplate(fp, clname, inclist, kFALSE, extrainfos);
3740  }
3741 
3742  TString name(1024);
3743  Int_t ltype = 10;
3744  Int_t ldata = 10;
3745  Int_t lt;
3746  Int_t ld;
3747  TIter next(fElements);
3748  TStreamerElement *element;
3749  Bool_t incRiostream = kFALSE;
3750  while ((element = (TStreamerElement*)next())) {
3751  //if (element->IsA() == TStreamerBase::Class()) continue;
3752  const char *ename = element->GetName();
3753  const char *colon2 = strstr(ename,"::");
3754  if (colon2) ename = colon2+2;
3755  name = ename;
3756  for (Int_t i=0;i < element->GetArrayDim();i++) {
3757  name += TString::Format("[%d]",element->GetMaxIndex(i));
3758  }
3759  ld = name.Length();
3760  lt = strlen(element->GetTypeName());
3761  if (ltype < lt) ltype = lt;
3762  if (ldata < ld) ldata = ld;
3763 
3764  //must include Riostream.h in case of an STL container
3765  if (!incRiostream && element->InheritsFrom(TStreamerSTL::Class())) {
3766  incRiostream = kTRUE;
3767  TMakeProject::AddInclude( fp, "Riostream.h", kFALSE, inclist);
3768  }
3769 
3770  //get include file name if any
3771  const char *include = element->GetInclude();
3772  if (!include[0]) continue;
3773 
3774  Bool_t greater = (include[0]=='<');
3775  include++;
3776 
3777  if (strncmp(include,"include/",8)==0) {
3778  include += 8;
3779  }
3780  if (strncmp(include,"include\\",9)==0) {
3781  include += 9;
3782  }
3783  if (strncmp(element->GetTypeName(),"pair<",strlen("pair<"))==0) {
3784  TMakeProject::AddInclude( fp, "utility", kTRUE, inclist);
3785  } else if (strncmp(element->GetTypeName(),"auto_ptr<",strlen("auto_ptr<"))==0) {
3786  TMakeProject::AddInclude( fp, "memory", kTRUE, inclist);
3787  } else {
3788  TString incName( include, strlen(include)-1 );
3789  incName = TMakeProject::GetHeaderName(incName,extrainfos);
3790  TMakeProject::AddInclude( fp, incName.Data(), greater, inclist);
3791  }
3792 
3793  if (strchr(element->GetTypeName(),'<')) {
3794  // This is a template, we need to check the template parameter.
3795  ninc += TMakeProject::GenerateIncludeForTemplate(fp, element->GetTypeName(), inclist, kFALSE, extrainfos);
3796  }
3797  }
3798  return ninc;
3799 }
3800 
3801 ////////////////////////////////////////////////////////////////////////////////
3802 /// Generate header file for the class described by this TStreamerInfo
3803 /// the function is called by TFile::MakeProject for each class in the file
3804 
3805 Int_t TStreamerInfo::GenerateHeaderFile(const char *dirname, const TList *subClasses, const TList *extrainfos)
3806 {
3807  // if (fClassVersion == -4) return 0;
3808  if ((fClass && fClass->GetCollectionType()) || TClassEdit::IsSTLCont(GetName())) return 0;
3809  if (strncmp(GetName(),"pair<",strlen("pair<"))==0) return 0;
3810  if (strncmp(GetName(),"auto_ptr<",strlen("auto_ptr<"))==0) return 0;
3811 
3812  TClass *cl = TClass::GetClass(GetName());
3813  if (cl) {
3814  if (cl->HasInterpreterInfo()) return 0; // skip known classes
3815  }
3816  Bool_t isTemplate = kFALSE;
3817  if (strchr(GetName(),':')) {
3818  UInt_t len = strlen(GetName());
3819  UInt_t nest = 0;
3820  UInt_t scope = 0;
3821  for(UInt_t i=len; i>0; --i) {
3822  switch(GetName()[i]) {
3823  case '>': ++nest; if (scope==0) { isTemplate = kTRUE; } break;
3824  case '<': --nest; break;
3825  case ':':
3826  if (nest==0 && GetName()[i-1]==':') {
3827  // We have a scope
3828  TString nsname(GetName(), i-1);
3829  cl = gROOT->GetClass(nsname);
3830  if (cl && (cl->Size()!=0 || (cl->Size()==0 && !cl->HasInterpreterInfo() /*empty 'base' class on file*/))) {
3831  // This class is actually nested.
3832  return 0;
3833  } else if (cl == 0 && extrainfos != 0) {
3834  TStreamerInfo *clinfo = (TStreamerInfo*)extrainfos->FindObject(nsname);
3835  if (clinfo && clinfo->GetClassVersion() == -5) {
3836  // This class is actually nested.
3837  return 0;
3838  }
3839  }
3840  ++scope;
3841  }
3842  break;
3843  }
3844  }
3845  }
3846  Bool_t needGenericTemplate = isTemplate && (fElements==0 || fElements->GetEntries()==0);
3847 
3848  if (gDebug) printf("generating code for class %s\n",GetName());
3849 
3850  // Open the file
3851 
3852  TString headername( TMakeProject::GetHeaderName( GetName(), extrainfos ) );
3853  TString filename;
3854  filename.Form("%s/%s.h",dirname,headername.Data());
3855 
3856  FILE *fp = fopen(filename.Data(),"w");
3857  if (!fp) {
3858  Error("MakeProject","Cannot open output file:%s\n",filename.Data());
3859  return 0;
3860  }
3861 
3862  filename.Form("%s/%sProjectHeaders.h",dirname,gSystem->BaseName(dirname));
3863  FILE *allfp = fopen(filename.Data(),"a");
3864  if (!allfp) {
3865  Error("MakeProject","Cannot open output file:%s\n",filename.Data());
3866  fclose(fp);
3867  return 0;
3868  }
3869  fprintf(allfp,"#include \"%s.h\"\n", headername.Data());
3870  fclose(allfp);
3871 
3872  char *inclist = new char[50000];
3873  inclist[0] = 0;
3874 
3875  // Generate class header.
3876  TDatime td;
3877  fprintf(fp,"//////////////////////////////////////////////////////////\n");
3878  fprintf(fp,"// This class has been generated by TFile::MakeProject\n");
3879  fprintf(fp,"// (%s by ROOT version %s)\n",td.AsString(),gROOT->GetVersion());
3880  fprintf(fp,"// from the StreamerInfo in file %s\n",gDirectory->GetFile()->GetName());
3881  fprintf(fp,"//////////////////////////////////////////////////////////\n");
3882  fprintf(fp,"\n");
3883  fprintf(fp,"\n");
3884  fprintf(fp,"#ifndef %s_h\n",headername.Data());
3885  fprintf(fp,"#define %s_h\n",headername.Data());
3886  TMakeProject::GenerateForwardDeclaration(fp, GetName(), inclist, kFALSE, needGenericTemplate, extrainfos);
3887  fprintf(fp,"\n");
3888 
3889  UInt_t ninc = 0;
3890  ninc += GenerateIncludes(fp, inclist, extrainfos);
3891  if (subClasses) {
3892  TIter subnext(subClasses);
3893  TStreamerInfo *subinfo;
3894  while ((subinfo = (TStreamerInfo*)subnext())) {
3895  ninc = subinfo->GenerateIncludes(fp, inclist, extrainfos);
3896  }
3897  }
3898  fprintf(fp,"\n");
3899 
3900  TString sourcename; sourcename.Form( "%s/%sProjectSource.cxx", dirname, gSystem->BaseName(dirname) );
3901  FILE *sfp = fopen( sourcename.Data(), "a" );
3902  if (sfp) {
3903  GenerateDeclaration(fp, sfp, subClasses);
3904  } else {
3905  Error("GenerateHeaderFile","Could not open %s for appending",sourcename.Data());
3906  }
3907  TMakeProject::GeneratePostDeclaration(fp, this, inclist);
3908 
3909  fprintf(fp,"#endif\n");
3910 
3911  delete [] inclist;
3912  fclose(fp);
3913  if (sfp) fclose(sfp);
3914  return 1;
3915 }
3916 
3917 ////////////////////////////////////////////////////////////////////////////////
3918 /// Compute data member offset.
3919 /// Return pointer to the Streamer function if one exists
3920 
3922 {
3923  TIter nextr(fClass->GetListOfRealData());
3924  char dmbracket[256];
3925  snprintf(dmbracket,255,"%s[",dm->GetName());
3926  Int_t offset = kMissing;
3927  if (!fClass->IsLoaded()) {
3928  // If the 'class' is not loaded, we do not have a TClass bootstrap and thus
3929  // the 'RealData' might not have enough information because of the lack
3930  // of proper ShowMember implementation.
3931  if (! (dm->Property() & kIsStatic) ) {
3932  // Give an offset only to non-static members.
3933  offset = dm->GetOffset();
3934  }
3935  }
3936  TRealData *rdm;
3937  while ((rdm = (TRealData*)nextr())) {
3938  char *rdmc = (char*)rdm->GetName();
3939  //next statement required in case a class and one of its parent class
3940  //have data members with the same name
3941  if (dm->IsaPointer() && rdmc[0] == '*') rdmc++;
3942 
3943  if (rdm->GetDataMember() != dm) continue;
3944  if (strcmp(rdmc,dm->GetName()) == 0) {
3945  offset = rdm->GetThisOffset();
3946  streamer = rdm->GetStreamer();
3947  break;
3948  }
3949  if (strcmp(rdm->GetName(),dm->GetName()) == 0) {
3950  if (rdm->IsObject()) {
3951  offset = rdm->GetThisOffset();
3952  streamer = rdm->GetStreamer();
3953  break;
3954  }
3955  }
3956  if (strstr(rdm->GetName(),dmbracket)) {
3957  offset = rdm->GetThisOffset();
3958  streamer = rdm->GetStreamer();
3959  break;
3960  }
3961  }
3962  return offset;
3963 }
3964 
3965 ////////////////////////////////////////////////////////////////////////////////
3966 /// Return the offset of the data member as indicated by this StreamerInfo.
3967 
3968 Int_t TStreamerInfo::GetOffset(const char *elementName) const
3969 {
3970  if (elementName == 0) return 0;
3971 
3972  Int_t offset = 0;
3973  TStreamerElement *elem = (TStreamerElement*)fElements->FindObject(elementName);
3974  if (elem) offset = elem->GetOffset();
3975 
3976  return offset;
3977 }
3978 
3979 ////////////////////////////////////////////////////////////////////////////////
3980 /// Return total size of all persistent elements of the class (with offsets).
3981 
3983 {
3984  return fSize;
3985 }
3986 
3987 ////////////////////////////////////////////////////////////////////////////////
3988 /// Return total size of all persistent elements of the class
3989 /// use GetSize if you want to get the real size in memory.
3990 
3992 {
3993  TIter next(fElements);
3994  TStreamerElement *element;
3995  Int_t asize = 0;
3996  while ((element = (TStreamerElement*)next())) {
3997  asize += element->GetSize();
3998  }
3999  return asize;
4000 }
4001 
4002 ////////////////////////////////////////////////////////////////////////////////
4003 /// Return the StreamerElement of "datamember" inside our
4004 /// class or any of its base classes.
4005 ///
4006 /// The offset information
4007 /// contained in the StreamerElement is related to its immediately
4008 /// containing class, so we return in 'offset' the offset inside
4009 /// our class.
4010 
4011 TStreamerElement* TStreamerInfo::GetStreamerElement(const char* datamember, Int_t& offset) const
4012 {
4013  if (!fElements) {
4014  return 0;
4015  }
4016 
4017  // Look first at the data members and base classes
4018  // of our class.
4019  TStreamerElement* element = (TStreamerElement*) fElements->FindObject(datamember);
4020  if (element) {
4021  offset = element->GetOffset();
4022  return element;
4023  }
4024 
4025  // Not found, so now try the data members and base classes
4026  // of the base classes of our class.
4027  if (fClass->HasDataMemberInfo()) {
4028  // Our class has a dictionary loaded, use it to search the base classes.
4029  TStreamerElement* base_element = 0;
4030  TBaseClass* base = 0;
4031  TClass* base_cl = 0;
4032  Int_t base_offset = 0;
4033  Int_t local_offset = 0;
4034  TIter nextb(fClass->GetListOfBases());
4035  // Iterate on list of base classes.
4036  while ((base = (TBaseClass*) nextb())) {
4037  base_cl = TClass::GetClass(base->GetName());
4038  base_element = (TStreamerElement*) fElements->FindObject(base->GetName());
4039  if (!base_cl || !base_element) {
4040  continue;
4041  }
4042  base_offset = base_element->GetOffset();
4043  element = ((TStreamerInfo*)base_cl->GetStreamerInfo())->GetStreamerElement(datamember, local_offset);
4044  if (element) {
4045  offset = base_offset + local_offset;
4046  return element;
4047  }
4048  }
4049  } else {
4050  // Our class's dictionary is not loaded. Search through the base class streamer elements.
4051  TIter next(fElements);
4052  TStreamerElement* curelem = 0;
4053  while ((curelem = (TStreamerElement*) next())) {
4054  if (curelem->InheritsFrom(TStreamerBase::Class())) {
4055  TClass* baseClass = curelem->GetClassPointer();
4056  if (!baseClass) {
4057  continue;
4058  }
4059  Int_t base_offset = curelem->GetOffset();
4060  Int_t local_offset = 0;
4061  TStreamerInfo *baseInfo;
4062  if (baseClass->Property() & kIsAbstract) {
4063  baseInfo = (TStreamerInfo*)baseClass->GetStreamerInfoAbstractEmulated();
4064  } else {
4065  baseInfo = (TStreamerInfo*)baseClass->GetStreamerInfo();
4066  }
4067  if (baseInfo) element = baseInfo->GetStreamerElement(datamember, local_offset);
4068  if (element) {
4069  offset = base_offset + local_offset;
4070  return element;
4071  }
4072  }
4073  }
4074  }
4075  return 0;
4076 }
4077 
4078 ////////////////////////////////////////////////////////////////////////////////
4079 /// <b>Obsolete</b>: this routine is obsolete and should not longer be used.
4080 ///
4081 /// TStreamerInfo holds two types of data structures
4082 /// - TObjArray* fElements; containing the list of all TStreamerElement
4083 /// objects for this class version.
4084 /// - ULong_t* fElem; containing the preprocessed information
4085 /// by TStreamerInfo::Compile In case consecutive data members
4086 /// are of the same type, the Compile function declares the consecutive
4087 /// elements as one single element in fElems.
4088 ///
4089 /// Example with the class TAttLine:
4090 /// ~~~{.cpp}
4091 /// TClass::GetClass("TAttLine")->GetStreamerInfo()->ls(); produces;
4092 /// StreamerInfo for class: TAttLine, version=1
4093 /// short fLineColor offset= 4 type= 2 line color
4094 /// short fLineStyle offset= 6 type= 2 line style
4095 /// short fLineWidth offset= 8 type= 2 line width
4096 /// i= 0, fLineColor type= 22, offset= 4, len=3, method=0
4097 /// ~~~
4098 /// For I/O implementations (eg. XML) , one has to know the original name
4099 /// of the data member. This function can be used to return a pointer
4100 /// to the original TStreamerElement object corresponding to the j-th
4101 /// element of a compressed array in fElems.
4102 /// Parameters description:
4103 /// - i: the serial number in array fElem
4104 /// - j: the element number in the array of consecutive types
4105 /// In the above example the class TAttLine has 3 consecutive data members
4106 /// of the same type "short". Compile makes one single array of 3 elements.
4107 /// To access the TStreamerElement for the second element
4108 /// of this array, one can call:
4109 /// ~~~{.cpp}
4110 /// auto el = GetStreamerElementReal(0,1);
4111 /// auto membername = el->GetName();
4112 /// ~~~
4113 /// This function is typically called from TBuffer, TXmlBuffer.
4114 
4116 {
4117  ::Obsolete("TStreamerInfo::GetStreamerElementReal", "v5-34-20", "v6-00-02");
4118 
4119  if (i < 0 || i >= fNdata) return 0;
4120  if (j < 0) return 0;
4121  if (!fElements) return 0;
4122  TStreamerElement *se = (TStreamerElement*)fCompOpt[i]->fElem;
4123  if (!se) return 0;
4124  Int_t nelems = fElements->GetEntriesFast();
4125  for (Int_t ise=0;ise < nelems;ise++) {
4126  if (se != (TStreamerElement*)fElements->UncheckedAt(ise)) continue;
4127  if (ise+j >= nelems) return 0;
4128  return (TStreamerElement*)fElements->UncheckedAt(ise+j);
4129  }
4130  return 0;
4131 }
4132 
4133 ////////////////////////////////////////////////////////////////////////////////
4134 /// Get the value from inside a collection.
4135 
4136 template <typename T>
4138 {
4139  if (type>=kConv && type<kSTL) {
4140  type -= kConv;
4141  }
4142  switch (type) {
4143  // basic types
4144  case kBool: {Bool_t *val = (Bool_t*)ladd; return T(*val);}
4145  case kChar: {Char_t *val = (Char_t*)ladd; return T(*val);}
4146  case kShort: {Short_t *val = (Short_t*)ladd; return T(*val);}
4147  case kInt: {Int_t *val = (Int_t*)ladd; return T(*val);}
4148  case kLong: {Long_t *val = (Long_t*)ladd; return T(*val);}
4149  case kLong64: {Long64_t *val = (Long64_t*)ladd; return T(*val);}
4150  case kFloat: {Float_t *val = (Float_t*)ladd; return T(*val);}
4151  case kFloat16: {Float_t *val = (Float_t*)ladd; return T(*val);}
4152  case kDouble: {Double_t *val = (Double_t*)ladd; return T(*val);}
4153  case kDouble32: {Double_t *val = (Double_t*)ladd; return T(*val);}
4154  case kUChar: {UChar_t *val = (UChar_t*)ladd; return T(*val);}
4155  case kUShort: {UShort_t *val = (UShort_t*)ladd; return T(*val);}
4156  case kUInt: {UInt_t *val = (UInt_t*)ladd; return T(*val);}
4157  case kULong: {ULong_t *val = (ULong_t*)ladd; return T(*val);}
4158 #if defined(_MSC_VER) && (_MSC_VER <= 1200)
4159  case kULong64: {Long64_t *val = (Long64_t*)ladd; return T(*val);}
4160 #else
4161  case kULong64: {ULong64_t *val= (ULong64_t*)ladd; return T(*val);}
4162 #endif
4163  case kBits: {UInt_t *val = (UInt_t*)ladd; return T(*val);}
4164 
4165  // array of basic types array[8]
4166  case kOffsetL + kBool: {Bool_t *val = (Bool_t*)ladd; return T(val[k]);}
4167  case kOffsetL + kChar: {Char_t *val = (Char_t*)ladd; return T(val[k]);}
4168  case kOffsetL + kShort: {Short_t *val = (Short_t*)ladd; return T(val[k]);}
4169  case kOffsetL + kInt: {Int_t *val = (Int_t*)ladd; return T(val[k]);}
4170  case kOffsetL + kLong: {Long_t *val = (Long_t*)ladd; return T(val[k]);}
4171  case kOffsetL + kLong64: {Long64_t *val = (Long64_t*)ladd; return T(val[k]);}
4172  case kOffsetL + kFloat: {Float_t *val = (Float_t*)ladd; return T(val[k]);}
4173  case kOffsetL + kFloat16: {Float_t *val = (Float_t*)ladd; return T(val[k]);}
4174  case kOffsetL + kDouble: {Double_t *val = (Double_t*)ladd; return T(val[k]);}
4175  case kOffsetL + kDouble32:{Double_t *val = (Double_t*)ladd; return T(val[k]);}
4176  case kOffsetL + kUChar: {UChar_t *val = (UChar_t*)ladd; return T(val[k]);}
4177  case kOffsetL + kUShort: {UShort_t *val = (UShort_t*)ladd; return T(val[k]);}
4178  case kOffsetL + kUInt: {UInt_t *val = (UInt_t*)ladd; return T(val[k]);}
4179  case kOffsetL + kULong: {ULong_t *val = (ULong_t*)ladd; return T(val[k]);}
4180 #if defined(_MSC_VER) && (_MSC_VER <= 1200)
4181  case kOffsetL + kULong64: {Long64_t *val = (Long64_t*)ladd; return T(val[k]);}
4182 #else
4183  case kOffsetL + kULong64:{ULong64_t *val= (ULong64_t*)ladd; return T(val[k]);}
4184 #endif
4185 
4186 #define READ_ARRAY(TYPE_t) \
4187  { \
4188  Int_t sub_instance, index; \
4189  Int_t instance = k; \
4190  if (len) { \
4191  index = instance / len; \
4192  sub_instance = instance % len; \
4193  } else { \
4194  index = instance; \
4195  sub_instance = 0; \
4196  } \
4197  TYPE_t **val =(TYPE_t**)(ladd); \
4198  return T((val[sub_instance])[index]); \
4199  }
4200 
4201  // pointer to an array of basic types array[n]
4205  case kOffsetP + kInt_t: READ_ARRAY(Int_t)
4208  case kOffsetP + kFloat16_t:
4210  case kOffsetP + kDouble32_t:
4216 #if defined(_MSC_VER) && (_MSC_VER <= 1200)
4218 #else
4220 #endif
4221 
4222  // array counter //[n]
4223  case kCounter: {Int_t *val = (Int_t*)ladd; return T(*val);}
4224  }
4225  return 0;
4226 }
4227 
4228 
4229 
4230 template Double_t TStreamerInfo::GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const;
4231 template Long64_t TStreamerInfo::GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const;
4232 template LongDouble_t TStreamerInfo::GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const;
4233 
4234 ////////////////////////////////////////////////////////////////////////////////
4235 /// Return value of element i in object at pointer.
4236 /// The function may be called in two ways:
4237 /// - method1 len < 0: i is assumed to be the TStreamerElement number i in StreamerInfo
4238 /// - method2 len >= 0: i is the type, address of variable is directly pointer.
4239 
4240 template <typename T>
4241 T TStreamerInfo::GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const
4242 {
4243  char *ladd;
4244  Int_t atype;
4245  if (len >= 0) {
4246  ladd = pointer;
4247  atype = i;
4248  } else {
4249  if (i < 0) return 0;
4250  ladd = pointer + fCompFull[i]->fOffset;
4251  atype = fCompFull[i]->fNewType;
4252  len = fCompFull[i]->fElem->GetArrayLength();
4253  if (atype == kSTL) {
4254  TClass *newClass = fCompFull[i]->fElem->GetNewClass();
4255  if (newClass == 0) {
4256  newClass = fCompFull[i]->fElem->GetClassPointer();
4257  }
4258  TClass *innerClass = newClass->GetCollectionProxy()->GetValueClass();
4259  if (innerClass) {
4260  return 0; // We don't know which member of the class we would want.
4261  } else {
4262  TVirtualCollectionProxy *proxy = newClass->GetCollectionProxy();
4263  // EDataType is a subset of TStreamerInfo::EReadWrite
4264  atype = (TStreamerInfo::EReadWrite)proxy->GetType();
4265  TVirtualCollectionProxy::TPushPop pop(proxy,ladd);
4266  Int_t nc = proxy->Size();
4267  if (j >= nc) return 0;
4268  char *element_ptr = (char*)proxy->At(j);
4269  return GetTypedValueAux<T>(atype,element_ptr,0,1);
4270  }
4271  }
4272  }
4273  return GetTypedValueAux<T>(atype,ladd,j,len);
4274 }
4275 
4276 ////////////////////////////////////////////////////////////////////////////////
4277 
4278 template Double_t TStreamerInfo::GetTypedValueClones<Double_t>(TClonesArray *clones, Int_t i, Int_t j, int k, Int_t eoffset) const;
4279 template Long64_t TStreamerInfo::GetTypedValueClones(TClonesArray *clones, Int_t i, Int_t j, int k, Int_t eoffset) const;
4280 template LongDouble_t TStreamerInfo::GetTypedValueClones(TClonesArray *clones, Int_t i, Int_t j, int k, Int_t eoffset) const;
4281 
4282 template <typename T>
4284 {
4285  // return value of element i in object number j in a TClonesArray and eventually
4286  // element k in a sub-array.
4287 
4288  Int_t nc = clones->GetEntriesFast();
4289  if (j >= nc) return 0;
4290 
4291  char *pointer = (char*)clones->UncheckedAt(j);
4292  char *ladd = pointer + eoffset + fCompFull[i]->fOffset;
4293  return GetTypedValueAux<T>(fCompFull[i]->fType,ladd,k,((TStreamerElement*)fCompFull[i]->fElem)->GetArrayLength());
4294 }
4295 
4296 template Double_t TStreamerInfo::GetTypedValueSTL(TVirtualCollectionProxy *cont, Int_t i, Int_t j, int k, Int_t eoffset) const;
4297 template Long64_t TStreamerInfo::GetTypedValueSTL(TVirtualCollectionProxy *cont, Int_t i, Int_t j, int k, Int_t eoffset) const;
4298 template LongDouble_t TStreamerInfo::GetTypedValueSTL(TVirtualCollectionProxy *cont, Int_t i, Int_t j, int k, Int_t eoffset) const;
4299 
4300 ////////////////////////////////////////////////////////////////////////////////
4301 /// Return value of element i in object number j in a TClonesArray and eventually
4302 /// element k in a sub-array.
4303 
4304 template <typename T>
4306 {
4307  Int_t nc = cont->Size();
4308  if (j >= nc) return 0;
4309 
4310  char *pointer = (char*)cont->At(j);
4311  char *ladd = pointer + eoffset + fCompFull[i]->fOffset;
4312  return GetTypedValueAux<T>(fCompFull[i]->fType,ladd,k,((TStreamerElement*)fCompFull[i]->fElem)->GetArrayLength());
4313 }
4314 
4315 template Double_t TStreamerInfo::GetTypedValueSTLP(TVirtualCollectionProxy *cont, Int_t i, Int_t j, int k, Int_t eoffset) const;
4316 template Long64_t TStreamerInfo::GetTypedValueSTLP(TVirtualCollectionProxy *cont, Int_t i, Int_t j, int k, Int_t eoffset) const;
4317 template LongDouble_t TStreamerInfo::GetTypedValueSTLP(TVirtualCollectionProxy *cont, Int_t i, Int_t j, int k, Int_t eoffset) const;
4318 
4319 ////////////////////////////////////////////////////////////////////////////////
4320 /// Return value of element i in object number j in a TClonesArray and eventually
4321 /// element k in a sub-array.
4322 
4323 template <typename T>
4325 {
4326  Int_t nc = cont->Size();
4327 
4328  if (j >= nc) return 0;
4329 
4330  char **ptr = (char**)cont->At(j);
4331  char *pointer = *ptr;
4332 
4333  char *ladd = pointer + eoffset + fCompFull[i]->fOffset;
4334  return GetTypedValueAux<T>(fCompFull[i]->fType,ladd,k,((TStreamerElement*)fCompFull[i]->fElem)->GetArrayLength());
4335 }
4336 
4337 ////////////////////////////////////////////////////////////////////////////////
4338 /// Insert new members as expressed in the array of TSchemaRule(s).
4339 
4340 void TStreamerInfo::InsertArtificialElements(std::vector<const ROOT::TSchemaRule*> &rules)
4341 {
4342  if (rules.empty()) return;
4343 
4344  TIter next(fElements);
4345  UInt_t count = 0;
4346 
4347  for(auto rule : rules) {
4348  if( rule->IsRenameRule() || rule->IsAliasRule() )
4349  continue;
4350  next.Reset();
4351  TStreamerElement *element;
4352  while ((element = (TStreamerElement*) next())) {
4353  if ( rule->HasTarget( element->GetName() ) ) {
4354 
4355  // Check whether this is an 'attribute' rule.
4356  if ( rule->GetAttributes()[0] != 0 ) {
4357  TString attr( rule->GetAttributes() );
4358  attr.ToLower();
4359  if (attr.Contains("owner")) {
4360  if (attr.Contains("notowner")) {
4362  } else {
4364  }
4365  }
4366 
4367  }
4368  break;
4369  }
4370  }
4371 
4372  // NOTE: Before adding the rule we should check that the source do
4373  // existing in this StreamerInfo.
4374  const TObjArray *sources = rule->GetSource();
4375  TIter input(sources);
4376  TObject *src;
4377  while((src = input())) {
4378  if ( !GetElements()->FindObject(src->GetName()) ) {
4379  // Missing source.
4380 #if 0 // Don't warn about not activating the rule. If don't warn the user can
4381  // have more flexibility in specifying when the rule applies and relying
4382  // on both the version number *and* the presence of the source members.
4383  // Activating this warning would for example mean that we need to carefully
4384  // tweak $ROOTSYS/etc/class.rules.
4385  TString ruleStr;
4386  rule->AsString(ruleStr);
4387  Warning("InsertArtificialElements","For class %s in StreamerInfo %d is missing the source data member %s when trying to apply the rule:\n %s",
4388  GetName(),GetClassVersion(),src->GetName(),ruleStr.Data());
4389  rule = 0;
4390 #endif
4391  break;
4392  }
4393  }
4394 
4395  if (!rule) continue;
4396 
4397  TStreamerArtificial *newel;
4398  typedef std::vector<TStreamerArtificial*> vec_t;
4399  vec_t toAdd;
4400 
4401  if (rule->GetTarget()==0) {
4402  TString newName;
4403  newName.Form("%s_rule%d",fClass->GetName(),count);
4404  newel = new TStreamerArtificial(newName,"",
4405  fClass->GetDataMemberOffset(newName),
4407  "void");
4409  newel->SetReadFunc( rule->GetReadFunctionPointer() );
4410  newel->SetReadRawFunc( rule->GetReadRawFunctionPointer() );
4411  toAdd.push_back(newel);
4412  } else {
4413  toAdd.reserve(rule->GetTarget()->GetEntries());
4414  TObjString * objstr = (TObjString*)(rule->GetTarget()->At(0));
4415  if (objstr) {
4416  TString newName = objstr->String();
4417  TString realDataName;
4418  if ( TDataMember* dm = fClass->GetDataMember( newName ) ) {
4419  TRealData::GetName(realDataName,dm);
4420  newel = new TStreamerArtificial(realDataName,"",
4421  fClass->GetDataMemberOffset(newName),
4423  fClass->GetDataMember( newName )->GetTypeName());
4424  newel->SetReadFunc( rule->GetReadFunctionPointer() );
4425  newel->SetReadRawFunc( rule->GetReadRawFunctionPointer() );
4426  toAdd.push_back(newel);
4427  } else {
4428  // This would be a completely new member (so it would need to be cached)
4429  // TOBEDONE
4430  }
4431  for(Int_t other = 1; other < rule->GetTarget()->GetEntries(); ++other) {
4432  objstr = (TObjString*)(rule->GetTarget()->At(other));
4433  if (objstr) {
4434  newName = objstr->String();
4435  if ( TDataMember* dm = fClass->GetDataMember( newName ) ) {
4436  TRealData::GetName(realDataName,dm);
4437  newel = new TStreamerArtificial(realDataName,"",
4438  fClass->GetDataMemberOffset(newName),
4440  fClass->GetDataMember( newName )->GetTypeName());
4441  toAdd.push_back(newel);
4442  }
4443  }
4444  }
4445  } // For each target of the rule
4446  }
4447  // Now find we with need to add them
4448  TIter s_iter(rule->GetSource());
4449  Int_t loc = -1;
4450  while( TObjString *s = (TObjString*)s_iter() ) {
4451  for(Int_t i = fElements->GetLast(); i >= 0 && (i+1) >= loc; --i) {
4452  if (s->String() == fElements->UncheckedAt(i)->GetName()) {
4453  if (loc == -1 || (i+1)>loc) {
4454  loc = i+1;
4455  }
4456  }
4457  }
4458  }
4459  if (loc == -1) {
4460  // Verify if the last one is not 'skipped'.
4461  for(Int_t i = fElements->GetLast(); i >= 0 && (i+1) >= loc; --i) {
4462  if ( ((TStreamerElement*)fElements->UncheckedAt(i))->GetNewType() != -2 ) {
4463  break;
4464  }
4465  loc = i;
4466  }
4467  }
4468  if (loc == -1) {
4469  for(vec_t::iterator iter = toAdd.begin(); iter != toAdd.end(); ++iter) {
4470  fElements->Add(*iter);
4471  }
4472  } else {
4473  R__TObjArray_InsertAt(fElements, toAdd, loc);
4474  }
4475  } // None of the target of the rule are on file.
4476 }
4477 
4478 ////////////////////////////////////////////////////////////////////////////////
4479 /// List the TStreamerElement list and also the precomputed tables
4480 /// if option contains the string "incOrig", also prints the original
4481 /// (non-optimized elements in the list of compiled elements.
4482 
4483 void TStreamerInfo::ls(Option_t *option) const
4484 {
4485  if (fClass && (fName != fClass->GetName())) {
4486  if (fClass->IsVersioned()) {
4487  Printf("\nStreamerInfo for conversion to %s from: %s, version=%d, checksum=0x%x",fClass->GetName(),GetName(),fClassVersion,GetCheckSum());
4488  } else {
4489  Printf("\nStreamerInfo for conversion to %s from: %s, checksum=0x%x",fClass->GetName(),GetName(),GetCheckSum());
4490  }
4491  } else {
4492  if (!fClass || fClass->IsVersioned()) {
4493  Printf("\nStreamerInfo for class: %s, version=%d, checksum=0x%x",GetName(),fClassVersion,GetCheckSum());
4494  } else {
4495  Printf("\nStreamerInfo for class: %s, checksum=0x%x",GetName(),GetCheckSum());
4496  }
4497  }
4498 
4499  if (fElements) {
4500  TIter next(fElements);
4501  TObject *obj;
4502  while ((obj = next()))
4503  obj->ls(option);
4504  }
4505  if (strstr(option,"full") != 0) {
4506  for (Int_t i=0; i < fNfulldata; ++i) {
4507  TStreamerElement *element = (TStreamerElement*)fCompFull[i]->fElem;
4508  TString sequenceType;
4509  element->GetSequenceType(sequenceType);
4510  // by definition of the loop (i+1) <= fNdata
4511  if (sequenceType.Length()) {
4512  sequenceType.Prepend(" [");
4513  sequenceType += "]";
4514  }
4515  Printf(" i=%2d, %-15s type=%3d, offset=%3d, len=%d, method=%ld%s",
4516  i,element->GetName(),fCompFull[i]->fType,fCompFull[i]->fOffset,fCompFull[i]->fLength,fCompFull[i]->fMethod,
4517  sequenceType.Data());
4518  }
4519 
4520  } else {
4521  Bool_t wantOrig = strstr(option,"incOrig") != 0;
4522  Bool_t optimized = kFALSE;
4523  for (Int_t i=0,j=0;i < fNdata;++i,++j) {
4524  TStreamerElement *element = (TStreamerElement*)fCompOpt[i]->fElem;
4525  TString sequenceType;
4526  element->GetSequenceType(sequenceType);
4527  // by definition of the loop (i+1) <= fNdata
4529  if (optimized) {
4530  // This was optimized.
4531  if (sequenceType.Length() != 0) {
4532  sequenceType += ',';
4533  }
4534  sequenceType += "optimized";
4535  }
4536  if (sequenceType.Length()) {
4537  sequenceType.Prepend(" [");
4538  sequenceType += "]";
4539  }
4540  Printf(" i=%2d, %-15s type=%3d, offset=%3d, len=%d, method=%ld%s",
4541  i,element->GetName(),fCompOpt[i]->fType,fCompOpt[i]->fOffset,fCompOpt[i]->fLength,fCompOpt[i]->fMethod,
4542  sequenceType.Data());
4543  if (optimized && wantOrig) {
4544  Bool_t done;
4545  do {
4546  element = (TStreamerElement*)fCompFull[j]->fElem;
4547  element->GetSequenceType(sequenceType);
4548  if (sequenceType.Length()) {
4549  sequenceType.Prepend(" [");
4550  sequenceType += "]";
4551  }
4552  Printf(" j=%2d, %-15s type=%3d, offset=%3d, len=%d, method=%ld%s",
4553  j,element->GetName(),fCompFull[j]->fType,fCompFull[j]->fOffset,fCompFull[j]->fLength,fCompFull[j]->fMethod,
4554  sequenceType.Data());
4555  ++j;
4556  done = j >= fNfulldata || ( (i+1 < fNdata) && fCompOpt[i+1]->fElem == fCompFull[j+1]->fElem );
4557  } while (!done);
4558 
4559  }
4560  }
4561  }
4562 }
4563 
4564 ////////////////////////////////////////////////////////////////////////////////
4565 /// An emulated object is created at address obj, if obj is null we
4566 /// allocate memory for the object.
4567 
4568 void* TStreamerInfo::New(void *obj)
4569 {
4570  //???FIX ME: What about varying length array elements?
4571 
4572  char* p = (char*) obj;
4573 
4574  TIter next(fElements);
4575 
4576  if (!p) {
4577  // Allocate and initialize the memory block.
4578  p = new char[fSize];
4579  memset(p, 0, fSize);
4580  }
4581 
4582  next.Reset();
4583  TStreamerElement* element = (TStreamerElement*) next();
4584 
4585  for (; element; element = (TStreamerElement*) next()) {
4586 
4587  // Skip elements which have not been allocated memory.
4588  if (element->GetOffset() == kMissing) {
4589  continue;
4590  }
4591 
4592  // Skip elements for which we do not have any class
4593  // information. FIXME: Document how this could happen.
4594  TClass* cle = element->GetClassPointer();
4595  if (!cle) {
4596  continue;
4597  }
4598 
4599  char* eaddr = p + element->GetOffset();
4600  Int_t etype = element->GetType();
4601 
4602  //cle->GetStreamerInfo(); //necessary in case "->" is not specified
4603 
4604  switch (etype) {
4605 
4606  case kAnyP:
4607  case kObjectP:
4608  case kSTLp:
4609  {
4610  // Initialize array of pointers with null pointers.
4611  char** r = (char**) eaddr;
4612  Int_t len = element->GetArrayLength();
4613  for (Int_t i = 0; i < len; ++i) {
4614  r[i] = 0;
4615  }
4616  }
4617  break;
4618 
4619  case kObjectp:
4620  case kAnyp:
4621  {
4622  // If the option "->" is given in the data member comment field
4623  // it is assumed that the object exists before reading data in,
4624  // so we create an object.
4625  if (cle != TClonesArray::Class()) {
4626  void** r = (void**) eaddr;
4627  *r = cle->New();
4628  } else {
4629  // In the case of a TClonesArray, the class name of
4630  // the contained objects must be specified in the
4631  // data member comment in this format:
4632  // TClonesArray* myVar; //->(className)
4633  const char* title = element->GetTitle();
4634  const char* bracket1 = strrchr(title, '(');
4635  const char* bracket2 = strrchr(title, ')');
4636  if (bracket1 && bracket2 && (bracket2 != (bracket1 + 1))) {
4637  Int_t len = bracket2 - (bracket1 + 1);
4638  char* clonesClass = new char[len+1];
4639  clonesClass[0] = '\0';
4640  strncat(clonesClass, bracket1 + 1, len);
4641  void** r = (void**) eaddr;
4642  *r = (void*) new TClonesArray(clonesClass);
4643  delete[] clonesClass;
4644  } else {
4645  //Warning("New", "No class name found for TClonesArray initializer in data member comment (expected \"//->(className)\"");
4646  void** r = (void**) eaddr;
4647  *r = (void*) new TClonesArray();
4648  }
4649  }
4650  }
4651  break;
4652 
4653  case kBase:
4654  {
4655  if (cle->Property() & kIsAbstract) {
4657  if (einfo) einfo->New(eaddr);
4658  } else {
4659  cle->New(eaddr);
4660  }
4661  break;
4662  }
4663  case kObject:
4664  case kAny:
4665  case kTObject:
4666  case kTString:
4667  case kTNamed:
4668  {
4669  cle->New(eaddr);
4670  }
4671  break;
4672 
4673  case kSTL:
4674  {
4675  if (strcmp(element->GetName(),"This")==0 &&
4676  !cle->GetCollectionProxy()) {
4677  // missing information, avoid infinite loop
4678  // by doing nothing ....
4679  } else {
4680  cle->New(eaddr);
4681  }
4682  }
4683  break;
4684 
4685  case kObject + kOffsetL:
4686  case kAny + kOffsetL:
4687  case kTObject + kOffsetL:
4688  case kTString + kOffsetL:
4689  case kTNamed + kOffsetL:
4690  case kSTL + kOffsetL:
4691  {
4692  Int_t size = cle->Size();
4693  char* r = eaddr;
4694  Int_t len = element->GetArrayLength();
4695  for (Int_t i = 0; i < len; ++i, r += size) {
4696  cle->New(r);
4697  }
4698  }
4699  break;
4700 
4701  } // switch etype
4702  } // for TIter next(fElements)
4703 
4704  for(int nbase = 0; nbase < fNVirtualInfoLoc; ++nbase) {
4705  *(TStreamerInfo**)(p + fVirtualInfoLoc[nbase]) = this;
4706  }
4707  ++fLiveCount;
4708  return p;
4709 }
4710 
4711 ////////////////////////////////////////////////////////////////////////////////
4712 /// An array of emulated objects is created at address ary, if ary is null,
4713 /// we allocate memory for the array.
4714 
4715 void* TStreamerInfo::NewArray(Long_t nElements, void *ary)
4716 {
4717  if (fClass == 0) {
4718  Error("NewArray", "TClass pointer is null!");
4719  return 0;
4720  }
4721 
4722  Int_t size = fClass->Size();
4723 
4724  char* p = (char*) ary;
4725 
4726  if (!p) {
4727  Long_t len = nElements * size + sizeof(Long_t)*2;
4728  p = new char[len];
4729  memset(p, 0, len);
4730  }
4731 
4732  // Store the array cookie
4733  Long_t* r = (Long_t*) p;
4734  r[0] = size;
4735  r[1] = nElements;
4736  char* dataBegin = (char*) &r[2];
4737 
4738  // Do a placement new for each element.
4739  p = dataBegin;
4740  for (Long_t cnt = 0; cnt < nElements; ++cnt) {
4741  New(p);
4742  p += size;
4743  } // for nElements
4744 
4745  return dataBegin;
4746 }
4747 
4748 
4749 #define DeleteBasicPointer(addr,element,name) \
4750  { \
4751  name **f = (name**)(addr); \
4752  int n = element->GetArrayLength() ? element->GetArrayLength() : 1;\
4753  for(int j=0;j<n;j++) { \
4754  delete [] f[j]; \
4755  f[j] = 0; \
4756  } \
4757  }
4758 
4759 ////////////////////////////////////////////////////////////////////////////////
4760 /// Internal part of the destructor.
4761 /// Destruct each of the datamembers in the same order
4762 /// as the implicit destructor would.
4763 
4764 void TStreamerInfo::DestructorImpl(void* obj, Bool_t dtorOnly)
4765 {
4766  R__ASSERT(obj != 0);
4767 
4768  char *p = (char*)obj;
4769 
4770  Int_t nelements = fElements->GetEntriesFast();
4771  //for (; ele; ele = (TStreamerElement*) next())
4772  for (Int_t elenum = nelements - 1; elenum >= 0; --elenum) {
4774  if (ele->GetOffset() == kMissing) continue;
4775  char* eaddr = p + ele->GetOffset();
4776 
4777 
4778  Int_t etype = ele->GetType();
4779 
4780  switch(etype) {
4796  case TStreamerInfo::kCharStar: DeleteBasicPointer(eaddr,ele,Char_t); continue;
4797  }
4798 
4799 
4800 
4801  TClass* cle = ele->GetClassPointer();
4802  if (!cle) continue;
4803 
4804 
4805  if (etype == kObjectp || etype == kAnyp) {
4806  // Destroy an array of pre-allocated objects.
4807  Int_t len = ele->GetArrayLength();
4808  if (!len) {
4809  len = 1;
4810  }
4811  void** r = (void**) eaddr;
4812  for (Int_t j = len - 1; j >= 0; --j) {
4813  if (r[j]) {
4814  cle->Destructor(r[j]);
4815  r[j] = 0;
4816  }
4817  }
4818  }
4819 
4820  if ((etype == kObjectP || etype == kAnyP || etype == kSTLp) && !ele->TestBit(TStreamerElement::kDoNotDelete)) {
4821  // Destroy an array of pointers to not-pre-allocated objects.
4822  Int_t len = ele->GetArrayLength();
4823  if (!len) {
4824  len = 1;
4825  }
4826  void** r = (void**) eaddr;
4827  for (Int_t j = len - 1; j >= 0; --j) {
4828  if (r[j]) {
4829  cle->Destructor(r[j]);
4830  r[j] = 0;
4831  }
4832  }
4833  }
4834 
4835  if (etype == kBase) {
4836  if (cle->Property() & kIsAbstract) {
4838  if (einfo) einfo->Destructor(eaddr, kTRUE);
4839  } else {
4840  cle->Destructor(eaddr, kTRUE);
4841  }
4842  }
4843 
4844  if (etype == kObject || etype == kAny ||
4845  etype == kTObject || etype == kTString || etype == kTNamed) {
4846  // A data member is destroyed, but not deleted.
4847  cle->Destructor(eaddr, kTRUE);
4848  }
4849 
4850  if (etype == kSTL) {
4851  // A data member is destroyed, but not deleted.
4853  if (!pr) {
4854  if (strcmp(ele->GetName(),"This")==0) {
4855  // missing information, avoid infinite loop
4856  // by doing nothing ....
4857  } else {
4858  cle->Destructor(eaddr, kTRUE);
4859  }
4860  } else {
4862  TVirtualCollectionProxy::TPushPop env(cle->GetCollectionProxy(), eaddr); // used for both this 'clear' and the 'clear' inside destructor.
4863  cle->GetCollectionProxy()->Clear(); // empty the collection without deleting the pointer
4864  pr->Destructor(eaddr, kTRUE);
4865  } else {
4866  pr->Destructor(eaddr, kTRUE);
4867  }
4868  }
4869  }
4870 
4871  if (etype == kObject + kOffsetL || etype == kAny + kOffsetL ||
4872  etype == kTObject + kOffsetL || etype == kTString + kOffsetL ||
4873  etype == kTNamed + kOffsetL || etype == kSTL + kOffsetL) {
4874  // For a data member which is an array of objects, we
4875  // destroy the objects, but do not delete them.
4876  Int_t len = ele->GetArrayLength();
4877  Int_t size = cle->Size();
4878  char* r = eaddr + (size * (len - 1));
4879  for (Int_t j = len - 1; j >= 0; --j, r -= size) {
4880  cle->Destructor(r, kTRUE);
4881  }
4882  }
4883  } // iter over elements
4884 
4885  if (!dtorOnly) {
4886  delete[] p;
4887  }
4888  --fLiveCount;
4889 }
4890 
4891 ////////////////////////////////////////////////////////////////////////////////
4892 /// Emulated destructor for this class.
4893 ///
4894 /// An emulated object is destroyed at address p.
4895 /// Destruct each of the datamembers in the same order
4896 /// as the implicit destructor would.
4897 
4898 void TStreamerInfo::Destructor(void* obj, Bool_t dtorOnly)
4899 {
4900  // Do nothing if passed a null pointer.
4901  if (obj == 0) return;
4902 
4903  char* p = (char*) obj;
4904 
4905  if (!dtorOnly && fNVirtualInfoLoc) {
4906  // !dtorOnly is used to filter out the case where this is called for
4907  // a base class or embedded object of the outer most class.
4908  TStreamerInfo *allocator = *(TStreamerInfo**)(p + fVirtualInfoLoc[0]);
4909  if (allocator != this) {
4910 
4911  Int_t baseoffset = allocator->GetClass()->GetBaseClassOffset(GetClass());
4912 
4913  p -= baseoffset;
4914  allocator->DestructorImpl(p, kFALSE);
4915  return;
4916  }
4917  }
4918  DestructorImpl(p, dtorOnly);
4919 }
4920 
4921 ////////////////////////////////////////////////////////////////////////////////
4922 /// Destroy an array of emulated objects, with optional delete.
4923 
4924 void TStreamerInfo::DeleteArray(void* ary, Bool_t dtorOnly)
4925 {
4926  // Do nothing if passed a null pointer.
4927  if (ary == 0) return;
4928 
4929  //???FIX ME: What about varying length arrays?
4930 
4931  Long_t* r = (Long_t*) ary;
4932  Long_t arrayLen = r[-1];
4933  Long_t size = r[-2];
4934  char* memBegin = (char*) &r[-2];
4935 
4936  char* p = ((char*) ary) + ((arrayLen - 1) * size);
4937  for (Long_t cnt = 0; cnt < arrayLen; ++cnt, p -= size) {
4938  // Destroy each element, but do not delete it.
4939  Destructor(p, kTRUE);
4940  } // for arrayItemSize
4941 
4942  if (!dtorOnly) {
4943  delete[] memBegin;
4944  }
4945 }
4946 
4947 ////////////////////////////////////////////////////////////////////////////////
4948 /// print value of element i in object at pointer
4949 /// The function may be called in two ways:
4950 /// -method1 len < 0
4951 /// i is assumed to be the TStreamerElement number i in StreamerInfo
4952 /// -method2 len >= 0
4953 /// i is the type
4954 /// address of variable is directly pointer.
4955 /// len is the number of elements to be printed starting at pointer.
4956 
4957 void TStreamerInfo::PrintValue(const char *name, char *pointer, Int_t i, Int_t len, Int_t lenmax) const
4958 {
4959  char *ladd;
4960  Int_t atype,aleng;
4961  printf(" %-15s = ",name);
4962 
4963  TStreamerElement * aElement = 0;
4964  Int_t *count = 0;
4965  if (len >= 0) {
4966  ladd = pointer;
4967  atype = i;
4968  aleng = len;
4969  } else {
4970  if (i < 0) {
4971  if (pointer==0) {
4972  printf("NULL\n");
4973  } else {
4974  const static TClassRef stringClass("string");
4975  if (fClass == stringClass) {
4976  std::string *st = (std::string*)(pointer);
4977  printf("%s\n",st->c_str());
4978  } else if (fClass == TString::Class()) {
4979  TString *st = (TString*)(pointer);
4980  printf("%s\n",st->Data());
4981  } else {
4982  printf("(%s*)0x%lx\n",GetName(),(ULong_t)pointer);
4983  }
4984  }
4985  return;
4986  }
4987  ladd = pointer + fCompFull[i]->fOffset;
4988  atype = fCompFull[i]->fNewType;
4989  aleng = fCompFull[i]->fLength;
4990  aElement = (TStreamerElement*)fCompFull[i]->fElem;
4991  count = (Int_t*)(pointer+fCompFull[i]->fMethod);
4992  }
4993  if (aleng > lenmax) aleng = lenmax;
4994 
4995  PrintValueAux(ladd,atype,aElement,aleng,count);
4996  printf("\n");
4997 }
4998 
4999 ////////////////////////////////////////////////////////////////////////////////
5000 /// Print value of element i in a TClonesArray.
5001 
5002 void TStreamerInfo::PrintValueClones(const char *name, TClonesArray *clones, Int_t i, Int_t eoffset, Int_t lenmax) const
5003 {
5004  if (!clones) {printf(" %-15s = \n",name); return;}
5005  printf(" %-15s = ",name);
5006  Int_t nc = clones->GetEntriesFast();
5007  if (nc > lenmax) nc = lenmax;
5008 
5009  Int_t offset = eoffset + fCompFull[i]->fOffset;
5010  TStreamerElement *aElement = (TStreamerElement*)fCompFull[i]->fElem;
5011  int aleng = fCompFull[i]->fLength;
5012  if (aleng > lenmax) aleng = lenmax;
5013 
5014  for (Int_t k=0;k < nc;k++) {
5015  char *pointer = (char*)clones->UncheckedAt(k);
5016  char *ladd = pointer+offset;
5017  Int_t *count = (Int_t*)(pointer+fCompFull[i]->fMethod);
5018  PrintValueAux(ladd,fCompFull[i]->fNewType,aElement, aleng, count);
5019  if (k < nc-1) printf(", ");
5020  }
5021  printf("\n");
5022 }
5023 
5024 ////////////////////////////////////////////////////////////////////////////////
5025 /// Print value of element i in a TClonesArray.
5026 
5027 void TStreamerInfo::PrintValueSTL(const char *name, TVirtualCollectionProxy *cont, Int_t i, Int_t eoffset, Int_t lenmax) const
5028 {
5029  if (!cont) {printf(" %-15s = \n",name); return;}
5030  printf(" %-15s = ",name);
5031  Int_t nc = cont->Size();
5032  if (nc > lenmax) nc = lenmax;
5033 
5034  Int_t offset = eoffset + fCompFull[i]->fOffset;
5035  TStreamerElement *aElement = (TStreamerElement*)fCompFull[i]->fElem;
5036  int aleng = fCompFull[i]->fLength;
5037  if (aleng > lenmax) aleng = lenmax;
5038 
5039  for (Int_t k=0;k < nc;k++) {
5040  char *pointer = (char*)cont->At(k);
5041  char *ladd = pointer+offset;
5042  Int_t *count = (Int_t*)(pointer+fCompFull[i]->fMethod);
5043  PrintValueAux(ladd,fCompFull[i]->fNewType,aElement, aleng, count);
5044  if (k < nc-1) printf(", ");
5045  }
5046  printf("\n");
5047 }
5048 
5049 ////////////////////////////////////////////////////////////////////////////////
5050 /// Stream an object of class TStreamerInfo.
5051 
5052 void TStreamerInfo::Streamer(TBuffer &R__b)
5053 {
5054  UInt_t R__s, R__c;
5055  if (R__b.IsReading()) {
5056  Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
5057  fOldVersion = R__v;
5058  if (R__v > 1) {
5059  //R__b.ReadClassBuffer(TStreamerInfo::Class(), this, R__v, R__s, R__c);
5060  R__b.ClassBegin(TStreamerInfo::Class(), R__v);
5061  R__b.ClassMember("TNamed");
5062  TNamed::Streamer(R__b);
5063  fName = TClassEdit::GetLong64_Name( fName.Data() ).c_str();
5064  R__b.ClassMember("fCheckSum","UInt_t");
5065  R__b >> fCheckSum;
5066  R__b.ClassMember("fClassVersion","Int_t");
5067  R__b >> fClassVersion;
5069  R__b.ClassMember("fElements","TObjArray*");
5070  R__b >> fElements;
5072  R__b.SetBufferOffset(R__s+R__c+sizeof(UInt_t));
5076 
5077  if (R__b.GetParent() && R__b.GetVersionOwner() < 50000)
5078  {
5079  // In some older files, the type of the TStreamerElement was not
5080  // as we (now) expect.
5081  Int_t nobjects = fElements->GetEntriesFast();
5082  TClass *basic = TStreamerBasicType::Class();
5083  for (Int_t i = 0; i < nobjects; i++) {
5084  TStreamerElement *el = (TStreamerElement*)fElements->UncheckedAt(i);
5085  TStreamerElement *rel = 0;
5086  if ( el->IsA() == basic ) {
5087  switch (el->GetType()) {
5088  default: break; /* nothing */
5089  case TStreamerInfo::kObject: /*61*/
5090  rel = new TStreamerObject(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5091  break;
5092  case TStreamerInfo::kAny: /*62*/
5093  rel = new TStreamerObjectAny(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5094  break;
5095  case TStreamerInfo::kObjectp: /* 63 */
5096  rel = new TStreamerObjectPointer(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5097  break;
5098  case TStreamerInfo::kObjectP: /* 64 */
5099  rel = new TStreamerObjectPointer(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5100  break;
5101  case TStreamerInfo::kTString: /* 65 */
5102  rel = new TStreamerObject(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5103  break;
5104  }
5105  if (rel) {
5106  (*fElements)[i] = rel;
5107  delete el;
5108  }
5109  }
5110  }
5111  }
5112  return;
5113  }
5114  //====process old versions before automatic schema evolution
5115  TNamed::Streamer(R__b);
5116  fName = TClassEdit::GetLong64_Name( fName.Data() ).c_str();
5117  R__b >> fCheckSum;
5118  R__b >> fClassVersion;
5120  R__b >> fElements;
5121  R__b.CheckByteCount(R__s, R__c, TStreamerInfo::IsA());
5122  } else {
5123  R__c = R__b.WriteVersion(TStreamerInfo::IsA(), kTRUE);
5125  R__b.ClassMember("TNamed");
5126  TNamed::Streamer(R__b);
5127  R__b.ClassMember("fCheckSum","UInt_t");
5128  R__b << fCheckSum;
5129  R__b.ClassMember("fClassVersion","Int_t");
5130  R__b << ((fClassVersion > 0) ? fClassVersion : -fClassVersion);
5131 
5132  //------------------------------------------------------------------------
5133  // Stream only non-artificial streamer elements
5134  //////////////////////////////////////////////////////////////////////////
5135 
5136  R__b.ClassMember("fElements","TObjArray*");
5137 #if NOTYET
5138  if (has_no_artificial_member) {
5139  R__b << fElements;
5140  } else
5141 #endif
5142  {
5144  Int_t nobjects = fElements->GetEntriesFast();
5145  TObjArray store( *fElements );
5146  TStreamerElement *el;
5147  for (Int_t i = 0; i < nobjects; i++) {
5149  if( el != 0 && (el->IsA() == TStreamerArtificial::Class() || el->TestBit(TStreamerElement::kRepeat))) {
5150  fElements->RemoveAt( i );
5151  } else if( el !=0 && (el->TestBit(TStreamerElement::kCache) && !el->TestBit(TStreamerElement::kWrite)) ) {
5152  fElements->RemoveAt( i );
5153  }
5154  }
5155  fElements->Compress();
5156  R__b << fElements;
5157  R__ASSERT(!fElements->IsOwner());
5158  *fElements = store;
5159  }
5161  R__b.SetByteCount(R__c, kTRUE);
5162  }
5163 }
5164 
5165 ////////////////////////////////////////////////////////////////////////////////
5166 /// Mark the classindex of the current file as using this TStreamerInfo.
5167 /// This function is deprecated and its functionality is now done by
5168 /// the overloads of TBuffer::TagStreamerInfo.
5169 
5171 {
5172  if (file) {
5173  // If the value of the atomic is kFALSE (equal to expected), change its value
5174  // to kTRUE and return true. Leave it as it is otherwise and return false.
5175  static std::atomic<Bool_t> onlyonce(kFALSE);
5176  Bool_t expected = kFALSE;
5177  if (onlyonce.compare_exchange_strong(expected,kTRUE)) {
5178  Warning("TagFile","This function is deprecated, use TBuffer::TagStreamerInfo instead");
5179  }
5180  TArrayC *cindex = file->GetClassIndex();
5181  Int_t nindex = cindex->GetSize();
5182  if (fNumber < 0 || fNumber >= nindex) {
5183  Error("TagFile","StreamerInfo: %s number: %d out of range[0,%d] in file: %s",
5184  GetName(),fNumber,nindex,file->GetName());
5185  return;
5186  }
5187  if (cindex->fArray[fNumber] == 0) {
5188  cindex->fArray[0] = 1;
5189  cindex->fArray[fNumber] = 1;
5190  }
5191  }
5192 }
5193 
5194 ////////////////////////////////////////////////////////////////////////////////
5195 
5196 #ifdef DOLOOP
5197 #undef DOLOOP
5198 #endif
5199 #define DOLOOP for (k = 0, pointer = arr[0]; k < narr; pointer = arr[++k])
5200 
5201 namespace {
5202  static void PrintCR(int j,Int_t aleng, UInt_t ltype)
5203  {
5204  if (j == aleng-1) printf("\n");
5205  else {
5206  printf(", ");
5207  if (j%ltype == ltype-1) printf("\n ");
5208  }
5209  }
5210 }
5211 
5212 ////////////////////////////////////////////////////////////////////////////////
5213 /// print value of element in object at pointer, type atype, leng aleng or *count
5214 /// The function may be called in two ways:
5215 /// -method1 len < 0
5216 /// i is assumed to be the TStreamerElement number i in StreamerInfo
5217 /// -method2 len >= 0
5218 /// i is the type
5219 /// address of variable is directly pointer.
5220 /// len is the number of elements to be printed starting at pointer.
5221 
5222 void TStreamerInfo::PrintValueAux(char *ladd, Int_t atype, TStreamerElement *aElement, Int_t aleng, Int_t *count)
5223 {
5224  int j;
5225 
5226  //assert(!((kOffsetP + kChar) <= atype && atype <= (kOffsetP + kBool) && count == 0));
5227  switch (atype) {
5228  // basic types
5229  case kBool: {Bool_t *val = (Bool_t* )ladd; printf("%d" ,*val); break;}
5230  case kChar: {Char_t *val = (Char_t* )ladd; printf("%d" ,*val); break;}
5231  case kShort: {Short_t *val = (Short_t* )ladd; printf("%d" ,*val); break;}
5232  case kInt: {Int_t *val = (Int_t* )ladd; printf("%d" ,*val); break;}
5233  case kLong: {Long_t *val = (Long_t* )ladd; printf("%ld",*val); break;}
5234  case kLong64: {Long64_t *val = (Long64_t* )ladd; printf("%lld",*val); break;}
5235  case kFloat: {Float_t *val = (Float_t* )ladd; printf("%f" ,*val); break;}
5236  case kFloat16: {Float_t *val = (Float_t* )ladd; printf("%f" ,*val); break;}
5237  case kDouble: {Double_t *val = (Double_t* )ladd; printf("%g" ,*val); break;}
5238  case kDouble32: {Double_t *val = (Double_t* )ladd; printf("%g" ,*val); break;}
5239  case kUChar: {UChar_t *val = (UChar_t* )ladd; printf("%u" ,*val); break;}
5240  case kUShort: {UShort_t *val = (UShort_t* )ladd; printf("%u" ,*val); break;}
5241  case kUInt: {UInt_t *val = (UInt_t* )ladd; printf("%u" ,*val); break;}
5242  case kULong: {ULong_t *val = (ULong_t* )ladd; printf("%lu",*val); break;}
5243  case kULong64: {ULong64_t *val = (ULong64_t*)ladd; printf("%llu",*val); break;}
5244  case kBits: {UInt_t *val = (UInt_t* )ladd; printf("%d" ,*val); break;}
5245 
5246  // array of basic types array[8]
5247  case kOffsetL + kBool: {Bool_t *val = (Bool_t* )ladd; for(j=0;j<aleng;j++) { printf("%c " ,val[j]); PrintCR(j,aleng,20); } break;}
5248  case kOffsetL + kChar: {Char_t *val = (Char_t* )ladd; for(j=0;j<aleng;j++) { printf("%c " ,val[j]); PrintCR(j,aleng,20); } break;}
5249  case kOffsetL + kShort: {Short_t *val = (Short_t* )ladd; for(j=0;j<aleng;j++) { printf("%d " ,val[j]); PrintCR(j,aleng,10); } break;}
5250  case kOffsetL + kInt: {Int_t *val = (Int_t* )ladd; for(j=0;j<aleng;j++) { printf("%d " ,val[j]); PrintCR(j,aleng,10); } break;}
5251  case kOffsetL + kLong: {Long_t *val = (Long_t* )ladd; for(j=0;j<aleng;j++) { printf("%ld ",val[j]); PrintCR(j,aleng, 5); } break;}
5252  case kOffsetL + kLong64: {Long64_t *val = (Long64_t* )ladd; for(j=0;j<aleng;j++) { printf("%lld ",val[j]);PrintCR(j,aleng, 5); } break;}
5253  case kOffsetL + kFloat: {Float_t *val = (Float_t* )ladd; for(j=0;j<aleng;j++) { printf("%f " ,val[j]); PrintCR(j,aleng, 5); } break;}
5254  case kOffsetL + kFloat16: {Float_t *val = (Float_t* )ladd; for(j=0;j<aleng;j++) { printf("%f " ,val[j]); PrintCR(j,aleng, 5); } break;}
5255  case kOffsetL + kDouble: {Double_t *val = (Double_t* )ladd; for(j=0;j<aleng;j++) { printf("%g " ,val[j]); PrintCR(j,aleng, 5); } break;}
5256  case kOffsetL + kDouble32:{Double_t *val = (Double_t* )ladd; for(j=0;j<aleng;j++) { printf("%g " ,val[j]); PrintCR(j,aleng, 5); } break;}
5257  case kOffsetL + kUChar: {UChar_t *val = (UChar_t* )ladd; for(j=0;j<aleng;j++) { printf("%u " ,val[j]); PrintCR(j,aleng,20); } break;}
5258  case kOffsetL + kUShort: {UShort_t *val = (UShort_t* )ladd; for(j=0;j<aleng;j++) { printf("%u " ,val[j]); PrintCR(j,aleng,10); } break;}
5259  case kOffsetL + kUInt: {UInt_t *val = (UInt_t* )ladd; for(j=0;j<aleng;j++) { printf("%u " ,val[j]); PrintCR(j,aleng, 5); } break;}
5260  case kOffsetL + kULong: {ULong_t *val = (ULong_t* )ladd; for(j=0;j<aleng;j++) { printf("%lu ",val[j]); PrintCR(j,aleng, 5); } break;}
5261  case kOffsetL + kULong64: {ULong64_t *val = (ULong64_t*)ladd; for(j=0;j<aleng;j++) { printf("%llu ",val[j]);PrintCR(j,aleng, 5); } break;}
5262  case kOffsetL + kBits: {UInt_t *val = (UInt_t* )ladd; for(j=0;j<aleng;j++) { printf("%d " ,val[j]); PrintCR(j,aleng, 5); } break;}
5263 
5264  // pointer to an array of basic types array[n]
5265  case kOffsetP + kBool: {Bool_t **val = (Bool_t** )ladd; for(j=0;j<*count;j++) { printf("%d " ,(*val)[j]); PrintCR(j,aleng,20); } break;}
5266  case kOffsetP + kChar: {Char_t **val = (Char_t** )ladd; for(j=0;j<*count;j++) { printf("%d " ,(*val)[j]); PrintCR(j,aleng,20); } break;}
5267  case kOffsetP + kShort: {Short_t **val = (Short_t** )ladd; for(j=0;j<*count;j++) { printf("%d " ,(*val)[j]); PrintCR(j,aleng,10); } break;}
5268  case kOffsetP + kInt: {Int_t **val = (Int_t** )ladd; for(j=0;j<*count;j++) { printf("%d " ,(*val)[j]); PrintCR(j,aleng,10); } break;}
5269  case kOffsetP + kLong: {Long_t **val = (Long_t** )ladd; for(j=0;j<*count;j++) { printf("%ld ",(*val)[j]); PrintCR(j,aleng, 5); } break;}
5270  case kOffsetP + kLong64: {Long64_t **val = (Long64_t**)ladd; for(j=0;j<*count;j++) { printf("%lld ",(*val)[j]); PrintCR(j,aleng, 5); } break;}
5271  case kOffsetP + kFloat: {Float_t **val = (Float_t** )ladd; for(j=0;j<*count;j++) { printf("%f " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5272  case kOffsetP + kFloat16: {Float_t **val = (Float_t** )ladd; for(j=0;j<*count;j++) { printf("%f " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5273  case kOffsetP + kDouble: {Double_t **val = (Double_t**)ladd; for(j=0;j<*count;j++) { printf("%g " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5274  case kOffsetP + kDouble32:{Double_t **val = (Double_t**)ladd; for(j=0;j<*count;j++) { printf("%g " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5275  case kOffsetP + kUChar: {UChar_t **val = (UChar_t** )ladd; for(j=0;j<*count;j++) { printf("%u " ,(*val)[j]); PrintCR(j,aleng,20); } break;}
5276  case kOffsetP + kUShort: {UShort_t **val = (UShort_t**)ladd; for(j=0;j<*count;j++) { printf("%u " ,(*val)[j]); PrintCR(j,aleng,10); } break;}
5277  case kOffsetP + kUInt: {UInt_t **val = (UInt_t** )ladd; for(j=0;j<*count;j++) { printf("%u " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5278  case kOffsetP + kULong: {ULong_t **val = (ULong_t** )ladd; for(j=0;j<*count;j++) { printf("%lu ",(*val)[j]); PrintCR(j,aleng, 5); } break;}
5279  case kOffsetP + kULong64: {ULong64_t**val = (ULong64_t**)ladd; for(j=0;j<*count;j++){ printf("%llu ",(*val)[j]); PrintCR(j,aleng, 5); } break;}
5280 
5281  // array counter //[n]
5282  case kCounter: {Int_t *val = (Int_t*)ladd; printf("%d",*val); break;}
5283  // char *
5284  case kCharStar:{
5285  char **val = (char**)ladd;
5286  if (*val) printf("%s",*val);
5287  break;
5288  }
5289  // Class * derived from TObject with comment field //->
5290  case kObjectp: {
5291  TObject **obj = (TObject**)(ladd);
5293  printf("(%s*)%lx",el ? el->GetClass()->GetName() : "unknown_type",(Long_t)(*obj));
5294  break;
5295  }
5296 
5297  // Class* derived from TObject
5298  case kObjectP: {
5299  TObject **obj = (TObject**)(ladd);
5301  printf("(%s*)%lx",el ? el->GetClass()->GetName() : "unknown_type",(Long_t)(*obj));
5302  break;
5303  }
5304 
5305  // Class derived from TObject
5306  case kObject: {
5307  TObject *obj = (TObject*)(ladd);
5308  printf("%s",obj->GetName());
5309  break;
5310  }
5311 
5312  // Special case for TString, TObject, TNamed
5313  case kTString: {
5314  TString *st = (TString*)(ladd);
5315  printf("%s",st->Data());
5316  break;
5317  }
5318  case kTObject: {
5319  TObject *obj = (TObject*)(ladd);
5320  printf("%s",obj->GetName());
5321  break;
5322  }
5323  case kTNamed: {
5324  TNamed *named = (TNamed*) (ladd);
5325  printf("%s/%s",named->GetName(),named->GetTitle());
5326  break;
5327  }
5328 
5329  // Class * not derived from TObject with comment field //->
5330  case kAnyp: {
5331  TObject **obj = (TObject**)(ladd);
5333  printf("(%s*)0x%lx",el ? el->GetClass()->GetName() : "unknown_type",(Long_t)(*obj));
5334  break;
5335  }
5336 
5337  // Class* not derived from TObject
5338  case kAnyP: {
5339  TObject **obj = (TObject**)(ladd);
5341  printf("(%s*)0x%lx",el ? el->GetClass()->GetName() : "unknown_type",(Long_t)(*obj));
5342  break;
5343  }
5344  // Any Class not derived from TObject
5345  case kOffsetL + kObjectp:
5346  case kOffsetL + kObjectP:
5347  case kAny: {
5348  printf("printing kAny case (%d)",atype);
5349 // if (aElement) {
5350 // TMemberStreamer *pstreamer = aElement->GetStreamer();
5351 // if (pstreamer == 0) {
5352 // //printf("ERROR, Streamer is null\n");
5353 // //aElement->ls();
5354 // break;
5355 // }
5356 // //(*pstreamer)(b,ladd,0);
5357 // }
5358  break;
5359  }
5360  // Base Class
5361  case kBase: {
5362  printf("printing kBase case (%d)",atype);
5363  //aElement->ReadBuffer(b,pointer);
5364  break;
5365  }
5366 
5367  case kOffsetL + kObject:
5368  case kOffsetL + kTString:
5369  case kOffsetL + kTObject:
5370  case kOffsetL + kTNamed:
5371  case kStreamer: {
5372  printf("printing kStreamer case (%d)",atype);
5373 // TMemberStreamer *pstreamer = aElement->GetStreamer();
5374 // if (pstreamer == 0) {
5375 // //printf("ERROR, Streamer is null\n");
5376 // //aElement->ls();
5377 // break;
5378 // }
5379 // //UInt_t start,count;
5380 // //b.ReadVersion(&start, &count);
5381 // //(*pstreamer)(b,ladd,0);
5382 // //b.CheckByteCount(start,count,IsA());
5383  break;
5384  }
5385 
5386  case kStreamLoop: {
5387  printf("printing kStreamLoop case (%d)",atype);
5388 // TMemberStreamer *pstreamer = aElement->GetStreamer();
5389 // if (pstreamer == 0) {
5390 // //printf("ERROR, Streamer is null\n");
5391 // //aElement->ls();
5392 // break;
5393 // }
5394  //Int_t *counter = (Int_t*)(count);
5395  //UInt_t start,count;
5396  ///b.ReadVersion(&start, &count);
5397  //(*pstreamer)(b,ladd,*counter);
5398  //b.CheckByteCount(start,count,IsA());
5399  break;
5400  }
5401  case kSTL: {
5402  if (aElement) {
5403  static TClassRef stringClass("string");
5404  if (ladd && aElement->GetClass() == stringClass) {
5405  std::string *st = (std::string*)(ladd);
5406  printf("%s",st->c_str());
5407  } else {
5408  printf("(%s*)0x%lx",aElement->GetClass()->GetName(),(Long_t)(ladd));
5409  }
5410  } else {
5411  printf("(unknown_type*)0x%lx",(Long_t)(ladd));
5412  }
5413  break;
5414  }
5415  }
5416 }
5417 
5418 ////////////////////////////////////////////////////////////////////////////////
5419 ///function called by the TClass constructor when replacing an emulated class
5420 ///by the real class
5421 
5422 void TStreamerInfo::Update(const TClass *oldcl, TClass *newcl)
5423 {
5424  TStreamerElement *element;
5425  TIter nextElement(GetElements());
5426  while ((element = (TStreamerElement*)nextElement())) {
5427  element->Update(oldcl,newcl);
5428  }
5429  for (Int_t i=0;i < fNslots;i++) {
5430  fComp[i].Update(oldcl,newcl);
5431  }
5432 }
5433 
5434 ////////////////////////////////////////////////////////////////////////////////
5435 /// Update the TClass pointer cached in this object.
5436 
5438 {
5439  if (fType != -1) {
5440  if (fClass == oldcl)
5441  fClass = newcl;
5442  else if (fClass == 0)
5443  fClass = TClass::GetClass(fClassName);
5444  }
5445 }
5446 
5447 ////////////////////////////////////////////////////////////////////////////////
5448 /// Generate emulated collection proxy for a given class.
5449 
5451 TStreamerInfo::GenEmulatedProxy(const char* class_name, Bool_t silent)
5452 {
5453  return TCollectionProxyFactory::GenEmulatedProxy(class_name, silent);
5454 }
5455 
5456 ////////////////////////////////////////////////////////////////////////////////
5457 /// Generate emulated class streamer for a given collection class.
5458 
5460 TStreamerInfo::GenEmulatedClassStreamer(const char* class_name, Bool_t silent)
5461 {
5462  return TCollectionProxyFactory::GenEmulatedClassStreamer(class_name, silent);
5463 }
5464 
5465 ////////////////////////////////////////////////////////////////////////////////
5466 /// Generate proxy from static functions.
5467 
5469 TStreamerInfo::GenExplicitProxy( const ::ROOT::TCollectionProxyInfo &info, TClass *cl )
5470 {
5472 }
5473 
5474 ////////////////////////////////////////////////////////////////////////////////
5475 /// Generate class streamer from static functions.
5476 
5478 TStreamerInfo::GenExplicitClassStreamer( const ::ROOT::TCollectionProxyInfo &info, TClass *cl )
5479 {
5481 }
Bool_t HasRuleWithSourceClass(const TString &source) const
Return True if we have any rule whose source class is &#39;source&#39;.
const int ndata
Describe Streamer information for one class version.
Definition: TStreamerInfo.h:43
Small helper to read a TBuffer containing a TClonesArray into any valid collection.
Int_t GetOffset(const char *) const
Return the offset of the data member as indicated by this StreamerInfo.
virtual const char * BaseName(const char *pathname)
Base name of a file name. Base name of /user/root is root.
Definition: TSystem.cxx:931
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
virtual void * New(void *obj=0)=0
virtual Bool_t IsTransient() const
Return kTRUE if the element represent an entity that is not written to the disk (transient members...
void SetBufferOffset(Int_t offset=0)
Definition: TBuffer.h:88
virtual Int_t GetCollectionType() const =0
virtual void Init(TVirtualStreamerInfo *obj=0)
Setup the element.
Bool_t IsReading() const
Definition: TBuffer.h:81
Int_t fClassVersion
Class version identifier.
Definition: TStreamerInfo.h:93
Bool_t IsForeign() const
Return kTRUE is the class is Foreign (the class does not have a Streamer method). ...
Definition: TClass.cxx:5584
TList * GetListOfBases()
Return list containing the TBaseClass(es) of a class.
Definition: TClass.cxx:3452
static std::atomic< Int_t > fgCount
Number of TStreamerInfo instances.
const char * GetCountClass() const
An array of TObjects.
Definition: TObjArray.h:37
static void R__TObjArray_InsertBefore(TObjArray *arr, TObject *newobj, TObject *oldobj)
const char * GetTypeNameBasic() const
Return type name of this element in case the type name is not a standard basic type, return the basic type name known to CINT.
virtual void ClassBegin(const TClass *, Version_t=-1)=0
T GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const
Return value of element i in object at pointer.
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition: TObject.cxx:847
virtual void SetOffset(Int_t offset)
TString GetTypeName()
Get basic type of typedef, e,g.
Definition: TDataType.cxx:149
Version_t fOldVersion
! Version of the TStreamerInfo object read from the file
long long Long64_t
Definition: RtypesCore.h:69
virtual Int_t GetProperties() const
static void PrintValueAux(char *ladd, Int_t atype, TStreamerElement *aElement, Int_t aleng, Int_t *count)
print value of element in object at pointer, type atype, leng aleng or *count The function may be cal...
void BuildEmulated(TFile *file)
Create an Emulation TStreamerInfo object.
TStreamerInfoActions::TActionSequence * fWriteMemberWiseVecPtr
! List of write action resulting from the compilation for use in member wise streaming.
short Version_t
Definition: RtypesCore.h:61
TStreamerElement * GetStreamerElement(const char *datamember, Int_t &offset) const
Return the StreamerElement of "datamember" inside our class or any of its base classes.
virtual Bool_t CompareContent(TClass *cl, TVirtualStreamerInfo *info, Bool_t warn, Bool_t complete, TFile *file)=0
const char * GetFullTypeName() const
Get full type description of data member, e,g.: "class TDirectory*".
TLine * line
virtual TClass * GetClass() const =0
Collectable string class.
Definition: TObjString.h:28
float Float_t
Definition: RtypesCore.h:53
Equal to TDataType&#39;s kchar.
virtual void SetSize(Int_t dsize)
const char Option_t
Definition: RtypesCore.h:62
virtual TClass * GetValueClass() const =0
virtual void Delete(Option_t *option="")
Remove all objects from the array AND delete all heap based objects.
Definition: TObjArray.cxx:329
All ROOT classes may have RTTI (run time type identification) support added.
Definition: TDataMember.h:31
TObject * GetParent() const
Return pointer to parent of this buffer.
Definition: TBuffer.cxx:231
static TString GetHeaderName(const char *name, const TList *extrainfos, Bool_t includeNested=kFALSE)
Return the header name containing the description of name.
double T(double x)
Definition: ChebyshevPol.h:34
R__EXTERN TVirtualMutex * gInterpreterMutex
Definition: TInterpreter.h:40
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition: TString.h:640
TClass * GetClassPointer(Bool_t load=kTRUE)
Get pointer to the base class TClass.
Definition: TBaseClass.cxx:63
T GetTypedValueSTL(TVirtualCollectionProxy *cont, Int_t i, Int_t j, Int_t k, Int_t eoffset) const
Return value of element i in object number j in a TClonesArray and eventually element k in a sub-arra...
Int_t GetUnitSize() const
Get the sizeof the underlying type of the data member (i.e.
unsigned short UShort_t
Definition: RtypesCore.h:36
Bool_t TestBit(UInt_t f) const
Definition: TObject.h:159
virtual TClass * GetClassPointer() const
Returns a pointer to the TClass of this element.
virtual void SetName(const char *name)
Set the name of the TNamed.
Definition: TNamed.cxx:131
TArrayC * GetClassIndex() const
Definition: TFile.h:197
TStreamerElement * GetStreamerElementReal(Int_t i, Int_t j) const
Obsolete: this routine is obsolete and should not longer be used.
UInt_t GetBaseCheckSum()
TVirtualStreamerInfo * GetStreamerInfo(Int_t version=0) const
returns a pointer to the TVirtualStreamerInfo object for version If the object does not exist...
Definition: TClass.cxx:4360
void Update(const TClass *oldcl, TClass *newcl)
Update the TClass pointer cached in this object.
static TClassStreamer * GenEmulatedClassStreamer(const char *class_name, Bool_t silent)
Generate emulated class streamer for a given collection class.
A ROOT file is a suite of consecutive data records (TKey instances) with a well defined format...
Definition: TFile.h:46
virtual Int_t GetEntries() const
Definition: TCollection.h:86
const char * GetTypeName() const
Get type of data member, e,g.: "class TDirectory*" -> "TDirectory".
Buffer base class used for serializing objects.
Definition: TBuffer.h:40
Bool_t HasInterpreterInfo() const
Definition: TClass.h:364
TClassStreamer * GetStreamer() const
Return the Streamer Class allowing streaming (if any).
Definition: TClass.cxx:2831
virtual void SetTypeName(const char *name)
#define R__ASSERT(e)
Definition: TError.h:96
virtual Int_t CheckByteCount(UInt_t startpos, UInt_t bcnt, const TClass *clss)=0
#define gROOT
Definition: TROOT.h:375
TList * GetListOfDataMembers(Bool_t load=kTRUE)
Return list containing the TDataMembers of a class.
Definition: TClass.cxx:3562
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition: TString.h:587
void SetReadFunc(ROOT::TSchemaRule::ReadFuncPtr_t val)
void ForceWriteInfo(TFile *file, Bool_t force=kFALSE)
Recursively mark streamer infos for writing to a file.
void PrintValueClones(const char *name, TClonesArray *clones, Int_t i, Int_t eoffset, Int_t lenmax=1000) const
Print value of element i in a TClonesArray.
void * New(void *obj=0)
An emulated object is created at address obj, if obj is null we allocate memory for the object...
EUniquePtrOffset
Basic string class.
Definition: TString.h:129
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition: TClass.cxx:2814
Int_t GetArrayLength() const
TVirtualStreamerInfo * GetCurrentStreamerInfo()
Definition: TClass.h:383
void ToLower()
Change string to lower-case.
Definition: TString.cxx:1099
void DestructorImpl(void *p, Bool_t dtorOnly)
Internal part of the destructor.
int Int_t
Definition: RtypesCore.h:41
static void GeneratePostDeclaration(FILE *fp, const TVirtualStreamerInfo *info, char *inclist)
Add to the header file anything that need to appear after the class declaration (this includes some #...
bool Bool_t
Definition: RtypesCore.h:59
void Reset()
Definition: TClassRef.h:72
virtual void Clear(const char *opt="")=0
Int_t GenerateHeaderFile(const char *dirname, const TList *subClasses=0, const TList *extrainfos=0)
Generate header file for the class described by this TStreamerInfo the function is called by TFile::M...
Cache the value in memory than is not part of the object but is accessible via a SchemaRule.
static const char * GetElementCounterStart(const char *dmTitle)
Given a comment/title declaring an array counter, for example: //[fArraySize] array of size fArraySiz...
Int_t fNdata
!number of optimized elements
Definition: TStreamerInfo.h:97
virtual void SetArrayDim(Int_t dim)
Set number of array dimensions.
ULong_t * fVirtualInfoLoc
![fNVirtualInfoLoc] Location of the pointer to the TStreamerInfo inside the object (when emulated) ...
TString & Prepend(const char *cs)
Definition: TString.h:609
Abstract base class for accessing the data-members of a class.
virtual UInt_t WriteVersion(const TClass *cl, Bool_t useBcnt=kFALSE)=0
TObject * At(Int_t idx) const
Definition: TObjArray.h:165
Int_t GetBaseVersion()
Int_t GetArrayDim() const
TClass * GetActualClass(const void *obj) const
Assuming that obj points to (the part of) an object that is of the type described by this streamerInf...
virtual EDataType GetType() const =0
Bool_t MatchLegacyCheckSum(UInt_t checksum) const
Return true if the checksum passed as argument is one of the checksum value produced by the older che...
void GetSequenceType(TString &type) const
Fill type with the string representation of sequence information including &#39;cached&#39;,&#39;repeat&#39;,&#39;write&#39; or &#39;nodelete&#39;.
virtual void SetMaxIndex(Int_t dim, Int_t max)
set maximum index for array with dimension dim
virtual void ForceWriteInfo(TFile *file, Bool_t force=kFALSE)=0
void Destructor(void *p, Bool_t dtorOnly=kFALSE)
Emulated destructor for this class.
static Proxy_t * GenExplicitProxy(const ::ROOT::TCollectionProxyInfo &info, TClass *cl)
Generate proxy from static functions.
void DeleteArray(void *p, Bool_t dtorOnly=kFALSE)
Destroy an array of emulated objects, with optional delete.
void PrintValue(const char *name, char *pointer, Int_t i, Int_t len, Int_t lenmax=1000) const
print value of element i in object at pointer The function may be called in two ways: -method1 len < ...
void Reset()
Definition: TCollection.h:156
TCompInfo ** fCompFull
![fElements->GetEntries()]
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition: TObject.cxx:687
TClass * GetClass() const
Definition: TClassRef.h:71
virtual TObject * FindObject(const char *name) const
Find an object in this list using its name.
Definition: TList.cxx:501
if object in a list can be deleted
Definition: TObject.h:58
void ComputeSize()
Compute total size of all persistent elements of the class.
virtual void Init(TVirtualStreamerInfo *obj=0)
Setup the element.
TStreamerInfoActions::TActionSequence * fReadMemberWise
! List of read action resulting from the compilation for use in member wise streaming.
Int_t fSize
!size of the persistent class
Definition: TStreamerInfo.h:96
Int_t GetBaseClassOffset(const TClass *toBase, void *address=0, bool isDerivedObject=true)
Definition: TClass.cxx:2709
virtual void ClassMember(const char *, const char *=0, Int_t=-1, Int_t=-1)=0
TObject * Last() const
Return the object in the last filled slot. Returns 0 if no entries.
Definition: TObjArray.cxx:479
Bool_t IsBasic() const
Return true if data member is a basic type, e.g. char, int, long...
virtual Int_t GetClassVersion() const =0
virtual TVirtualCollectionProxy * GenEmulatedProxy(const char *class_name, Bool_t silent)
Generate emulated collection proxy for a given class.
friend class TClonesArray
Definition: TObject.h:200
#define READ_ARRAY(TYPE_t)
Int_t GetVersion() const
Definition: TFile.h:216
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString...
Definition: TString.cxx:2345
void Class()
Definition: Class.C:29
virtual TClassStreamer * GenEmulatedClassStreamer(const char *class_name, Bool_t silent)
Generate emulated class streamer for a given collection class.
The TNamed class is the base class for all named ROOT classes.
Definition: TNamed.h:29
virtual TVirtualCollectionProxy * GenExplicitProxy(const ::ROOT::Detail::TCollectionProxyInfo &info, TClass *cl)
Generate proxy from static functions.
virtual TObject * FindObject(const char *name) const
Find an object in this collection using its name.
Definition: TObjArray.cxx:396
virtual Int_t GetVersionOwner() const =0
ECheckSum
Definition: TClass.h:92
TVirtualStreamerInfo * GetStreamerInfoAbstractEmulated(Int_t version=0) const
For the case where the requestor class is emulated and this class is abstract, returns a pointer to t...
Definition: TClass.cxx:4443
Long_t Property() const
Get property description word. For meaning of bits see EProperty.
Bool_t IsLoaded() const
Return true if the shared library of this class is currently in the a process&#39;s memory.
Definition: TClass.cxx:5549
Int_t GetDelta()
Get offset from "this" to part of base class.
Definition: TBaseClass.cxx:75
#define DeleteBasicPointer(addr, element, name)
void Clear()
Clear string without changing its capacity.
Definition: TString.cxx:1150
const char * GetCountClass() const
virtual void SetNewClass(TClass *cl)
EState GetState() const
Definition: TClass.h:433
Int_t fNfulldata
!number of elements
Definition: TStreamerInfo.h:98
TString & Append(const char *cs)
Definition: TString.h:497
std::vector< std::vector< double > > Data
virtual void Destructor(void *p, Bool_t dtorOnly=kFALSE) const
Eventhough BIT(13) is taken up by TObject (to preserverse forward compatibility)
Long_t GetThisOffset() const
Definition: TRealData.h:55
TStreamerInfoActions::TActionSequence * fReadObjectWise
! List of read action resulting from the compilation.
TDataType * GetDataType() const
Definition: TDataMember.h:72
virtual TClassStreamer * GenExplicitClassStreamer(const ::ROOT::Detail::TCollectionProxyInfo &info, TClass *cl)
Generate class streamer from static functions.
static UInt_t GenerateForwardDeclaration(FILE *fp, const char *clname, char *inclist, Bool_t implementEmptyClass, Bool_t needGenericTemplate, const TList *extrainfos)
Insert a (complete) forward declaration for the class &#39;clname&#39;.
static void R__WriteMoveConstructorBody(FILE *file, const TString &protoname, TIter &next)
Write down the body of the &#39;move&#39; constructor.
void SetCountClass(const char *clname)
void RegisterStreamerInfo(TVirtualStreamerInfo *info)
Register the StreamerInfo in the given slot, change the State of the TClass as appropriate.
Definition: TClass.cxx:6830
Bool_t operator!=(const TDatime &d1, const TDatime &d2)
Definition: TDatime.h:104
TVirtualStreamerInfo * GetBaseStreamerInfo() const
UInt_t fCheckSum
Checksum of original class.
Definition: TStreamerInfo.h:92
Int_t GetSizeElements() const
Return total size of all persistent elements of the class use GetSize if you want to get the real siz...
const TObjArray * GetStreamerInfos() const
Definition: TClass.h:437
void Obsolete(const char *method, const char *asOfVers, const char *removedFromVers) const
Use this method to declare a method obsolete.
Definition: TObject.cxx:935
void GenerateDeclaration(FILE *fp, FILE *sfp, const TList *subClasses, Bool_t top=kTRUE)
Write the Declaration of class.
static void AddInclude(FILE *fp, const char *header, Bool_t system, char *inclist)
Add an include statement, if it has not already been added.
virtual void ls(Option_t *option="") const
The ls function lists the contents of a class on stdout.
Definition: TObject.cxx:485
virtual void Update(const TClass *oldClass, TClass *newClass)
function called by the TClass constructor when replacing an emulated class by the real class ...
T GetTypedValueSTLP(TVirtualCollectionProxy *cont, Int_t i, Int_t j, Int_t k, Int_t eoffset) const
Return value of element i in object number j in a TClonesArray and eventually element k in a sub-arra...
static T GetTypedValueAux(Int_t type, void *ladd, int k, Int_t len)
Get the value from inside a collection.
virtual void SetStreamer(TMemberStreamer *streamer)
set pointer to Streamer function for this element
Int_t GetMaxIndex(Int_t dim) const
Return maximum index for array dimension "dim".
A doubly linked list.
Definition: TList.h:43
void InsertArtificialElements(std::vector< const ROOT::TSchemaRule *> &rules)
Insert new members as expressed in the array of TSchemaRule(s).
Int_t GetType(Int_t id) const
static void R__WriteDestructorBody(FILE *file, TIter &next)
TClass * GetBaseClass(const char *classname)
Return pointer to the base class "classname".
Definition: TClass.cxx:2575
Int_t GetType() const
Definition: TDataType.h:68
virtual void Update(const TClass *oldClass, TClass *newClass)
function called by the TClass constructor when replacing an emulated class by the real class ...
void BuildRealData(void *pointer=0, Bool_t isTransient=kFALSE)
Build a full list of persistent data members.
Definition: TClass.cxx:1943
TClass * fClass
!pointer to class
void SetErrorMessage(const char *msg)
Int_t GetLast() const
Return index of last object in array.
Definition: TObjArray.cxx:528
static void R__TObjArray_InsertAt(TObjArray *arr, TObject *obj, Int_t at)
void ResetClassVersion(TClass *, const char *, Short_t)
Global function to update the version number.
TObjArray * fElements
Array of TStreamerElements.
virtual const char * GetInclude() const
UInt_t GenerateIncludes(FILE *fp, char *inclist, const TList *extrainfos)
Add to the header file, the #include need for this class.
virtual TObject * FindObject(const char *name) const
Must be redefined in derived classes.
Definition: TObject.cxx:328
virtual void AddAtAndExpand(TObject *obj, Int_t idx)
Add object at position idx.
Definition: TObjArray.cxx:222
TClass * GetClass() const
TRandom2 r(17)
TVirtualStreamerInfo * FindStreamerInfo(TObjArray *arr, UInt_t checksum) const
Find the TVirtualStreamerInfo in the StreamerInfos corresponding to checksum.
Definition: TClass.cxx:6617
R__EXTERN TSystem * gSystem
Definition: TSystem.h:539
void BuildOld()
rebuild the TStreamerInfo structure
void Clear(Option_t *)
If opt contains &#39;built&#39;, reset this StreamerInfo as if Build or BuildOld was never called on it (usef...
UInt_t GetCheckSum() const
Int_t GetSize() const
Definition: TArray.h:47
Basic data type descriptor (datatype information is obtained from CINT).
Definition: TDataType.h:44
void SetCountClass(const char *clname)
void CallShowMembers(const void *obj, TMemberInspector &insp, Bool_t isTransient) const
Emulated a call ShowMembers() on the obj of this class type, passing insp and parent.
virtual TObject * RemoveAt(Int_t idx)
Remove object at index idx.
Definition: TObjArray.cxx:630
Int_t fOnFileClassVersion
!Class version identifier as stored on file.
Definition: TStreamerInfo.h:94
virtual Bool_t HasPointers() const =0
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition: TObject.cxx:436
TDataMember * GetDataMember() const
Definition: TRealData.h:53
void Destructor(void *obj, Bool_t dtorOnly=kFALSE)
Explicitly call destructor for object.
Definition: TClass.cxx:5063
void IgnoreTObjectStreamer(Bool_t ignore=kTRUE)
When the class kIgnoreTObjectStreamer bit is set, the automatically generated Streamer will not call ...
Definition: TClass.cxx:4569
const TMatches FindRules(const TString &source) const
Return all the rules that are about the given &#39;source&#39; class.
TMemberStreamer * GetStreamer() const
Return the associate streamer object.
Definition: TRealData.cxx:115
Int_t GetMaxIndex(Int_t i) const
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition: TString.cxx:2332
virtual Bool_t BuildFor(const TClass *cl)
Check if we can build this for foreign class - do we have some rules to do that.
unsigned int UInt_t
Definition: RtypesCore.h:42
Int_t GetDataMemberOffset(TDataMember *dm, TMemberStreamer *&streamer) const
Compute data member offset.
Int_t GetEntriesFast() const
Definition: TObjArray.h:64
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:873
const Handle_t kNone
Definition: GuiTypes.h:87
Ssiz_t Length() const
Definition: TString.h:388
Int_t Size() const
Return size of object of this class.
Definition: TClass.cxx:5348
const TObjArray * GetTarget() const
Get the target data members of this rule (i.e. the in memory data member).
TSubString Strip(EStripType s=kTrailing, char c=' ') const
Return a substring of self stripped at beginning and/or end.
Definition: TString.cxx:1080
short Short_t
Definition: RtypesCore.h:35
The TRealData class manages the effective list of all data members for a given class.
Definition: TRealData.h:30
Bool_t CanIgnoreTObjectStreamer()
Definition: TClass.h:348
static void R__WriteConstructorBody(FILE *file, TIter &next)
Int_t GetArrayDim() const
Return number of array dimensions.
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:71
virtual void SetByteCount(UInt_t cntpos, Bool_t packInVersion=kFALSE)=0
long double LongDouble_t
Definition: RtypesCore.h:57
ROOT::ESTLType GetCollectionType() const
Return the &#39;type&#39; of the STL the TClass is representing.
Definition: TClass.cxx:2803
static TVirtualCollectionProxy * GenEmulatedProxy(const char *class_name, Bool_t silent)
Generate emulated collection proxy for a given class.
Long_t GetOffset() const
Get offset from "this".
Long_t Property() const
Set TObject::fBits and fStreamerType to cache information about the class.
Definition: TClass.cxx:5675
TString fName
Definition: TNamed.h:32
TString & String()
Definition: TObjString.h:49
virtual void AddAt(TObject *obj, Int_t idx)
Add object at position ids.
Definition: TObjArray.cxx:239
virtual void Init(TVirtualStreamerInfo *obj=0)
Initliaze the element.
Bool_t MatchLegacyCheckSum(UInt_t checksum) const
Return true if the checksum passed as argument is one of the checksum value produced by the older che...
Definition: TClass.cxx:6054
Each class (see TClass) has a linked list of its base class(es).
Definition: TBaseClass.h:31
#define Printf
Definition: TGeoToOCC.h:18
TCompInfo * fComp
![fNslots with less than fElements->GetEntries()*1.5 used] Compiled info
TStreamerInfoActions::TActionSequence * fWriteMemberWise
! List of write action resulting from the compilation for use in member wise streaming.
Bool_t fIsBuilt
true if the StreamerInfo has been optimized
#define R__LOCKGUARD2(mutex)
const Bool_t kFALSE
Definition: RtypesCore.h:92
PyObject * fType
TStreamerElement * fElem
Not Owned.
Definition: TStreamerInfo.h:55
T GetTypedValueClones(TClonesArray *clones, Int_t i, Int_t j, Int_t k, Int_t eoffset) const
virtual void Destructor(void *p, Bool_t dtorOnly=kFALSE)=0
const char * GetTrueTypeName() const
Get full type description of data member, e,g.: "class TDirectory*".
static UInt_t GenerateIncludeForTemplate(FILE *fp, const char *clname, char *inclist, Bool_t forward, const TList *extrainfos)
Add to the header file, the #include needed for the argument of this template.
TString & Remove(Ssiz_t pos)
Definition: TString.h:621
std::atomic< Bool_t > fIsCompiled
true if the StreamerInfo has been &#39;built&#39; (i.e. has all the StreamerElements it should have) ...
long Long_t
Definition: RtypesCore.h:50
Bool_t CallShowMembers(const void *obj, TMemberInspector &insp, Bool_t isTransient=kFALSE) const
Call ShowMembers() on the obj of this class type, passing insp and parent.
Definition: TClass.cxx:2117
Version_t GetClassVersion() const
Definition: TClass.h:372
void Build()
Build the I/O data structure for the current class version.
TObject * UncheckedAt(Int_t i) const
Definition: TObjArray.h:89
#define ClassImp(name)
Definition: Rtypes.h:336
double f(double x)
Int_t GetSize() const
Return total size of all persistent elements of the class (with offsets).
double Double_t
Definition: RtypesCore.h:55
virtual TObjArray * GetElements() const =0
Int_t fNslots
!total numbrer of slots in fComp.
Definition: TStreamerInfo.h:99
TStreamerInfoActions::TActionSequence * fReadMemberWiseVecPtr
! List of read action resulting from the compilation for use in member wise streaming.
virtual Bool_t IsaPointer() const
TStreamerInfoActions::TActionSequence * fWriteObjectWise
! List of write action resulting from the compilation.
void RemoveStreamerInfo(Int_t slot)
Remove and delete the StreamerInfo in the given slot.
Definition: TClass.cxx:6854
Long_t GetDataMemberOffset(const char *membername) const
return offset for member name.
Definition: TClass.cxx:3253
virtual const char * GetFullName() const
Return element name including dimensions, if any Note that this function stores the name into a stati...
int type
Definition: TGX11.cxx:120
unsigned long long ULong64_t
Definition: RtypesCore.h:70
virtual Int_t GetSize() const
Returns size of this element in bytes.
void SetNewBaseClass(TClass *cl)
TList * GetListOfRealData() const
Definition: TClass.h:395
Bool_t HasDataMemberInfo() const
Definition: TClass.h:361
const char * GetParent() const
unsigned long ULong_t
Definition: RtypesCore.h:51
virtual Bool_t HasCounter() const
virtual Bool_t IsBase() const
Return kTRUE if the element represent a base class.
EDataType
Definition: TDataType.h:28
virtual void SetType(Int_t dtype)
Int_t fNVirtualInfoLoc
! Number of virtual info location to update.
virtual void * At(UInt_t idx)=0
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition: TString.h:572
const char * AsString() const
Return the date & time as a string (ctime() format).
Definition: TDatime.cxx:101
#define R__LOCKGUARD(mutex)
void InspectMember(const T &obj, const char *name, Bool_t isTransient)
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition: TClass.cxx:2885
void Compile()
loop on the TStreamerElement list regroup members with same type Store predigested information into l...
Bool_t IsPersistent() const
Definition: TDataMember.h:87
void TagFile(TFile *fFile)
Mark the classindex of the current file as using this TStreamerInfo.
virtual TObject * Clone(const char *newname="") const
Make a clone of an object using the Streamer facility.
Definition: TNamed.cxx:65
const TList * GetStreamerInfoCache()
Returns the cached list of StreamerInfos used in this file.
Definition: TFile.cxx:1304
Mother of all ROOT objects.
Definition: TObject.h:37
TObjArray * GetElements() const
void ls(Option_t *option="") const
List the TStreamerElement list and also the precomputed tables if option contains the string "incOrig...
virtual void Inspect(TClass *cl, const char *parent, const char *name, const void *addr)
Int_t GetNewType() const
Int_t IsSTLContainer()
The return type is defined in TDictionary (kVector, kList, etc.)
virtual UInt_t Size() const =0
TClassRef is used to implement a permanent reference to a TClass object.
Definition: TClassRef.h:29
char Char_t
Definition: RtypesCore.h:29
Int_t GetClassVersion() const
static TString UpdateAssociativeToVector(const char *name)
If we have a map, multimap, set or multiset, plus unordered partners, and the key is a class...
virtual const char * GetTitle() const
Returns title of object.
Definition: TObject.cxx:408
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition: TClass.cxx:5575
Int_t GetOnFileClassVersion() const
An array of clone (identical) objects.
Definition: TClonesArray.h:32
Int_t fNumber
!Unique identifier
Definition: TStreamerInfo.h:95
void BuildCheck(TFile *file=0)
Check if built and consistent with the class dictionary.
virtual ~TStreamerInfo()
TStreamerInfo dtor.
const char * GetTypeName() const
Int_t GetNewType(Int_t id) const
virtual void ClassEnd(const TClass *)=0
Definition: file.py:1
const char * GetArrayIndex() const
If the data member is pointer and has a valid array size in its comments GetArrayIndex returns a stri...
TClass * GetNewClass() const
Int_t Size() const
Get size of basic typedef&#39;ed type.
Definition: TDataType.cxx:366
Bool_t IsVersioned() const
Definition: TClass.h:453
Char_t * fArray
Definition: TArrayC.h:30
virtual void SetNewType(Int_t dtype)
static TStreamerBasicType * GetElementCounter(const char *countName, TClass *cl)
Get pointer to a TStreamerBasicType in TClass *cl static function.
#define snprintf
Definition: civetweb.c:822
Int_t GetEntries() const
Return the number of objects in array (i.e.
Definition: TObjArray.cxx:494
R__EXTERN Int_t gDebug
Definition: Rtypes.h:83
void PrintValueSTL(const char *name, TVirtualCollectionProxy *cont, Int_t i, Int_t eoffset, Int_t lenmax=1000) const
Print value of element i in a TClonesArray.
void * NewArray(Long_t nElements, void *ary=0)
An array of emulated objects is created at address ary, if ary is null, we allocate memory for the ar...
void Add(TObject *obj)
Definition: TObjArray.h:73
const Int_t kMaxLen
TCompInfo ** fCompOpt
![fNdata]
#define gDirectory
Definition: TDirectory.h:211
double result[121]
TDataMember * GetDataMember(const char *datamember) const
Return pointer to datamember object with name "datamember".
Definition: TClass.cxx:3225
void ResetBit(UInt_t f)
Definition: TObject.h:158
unsigned char UChar_t
Definition: RtypesCore.h:34
const ROOT::Detail::TSchemaRuleSet * GetSchemaRules() const
Return the set of the schema rules if any.
Definition: TClass.cxx:1844
UInt_t GetCheckSum(ECheckSum code=kCurrentCheckSum) const
Call GetCheckSum with validity check.
Definition: TClass.cxx:6065
virtual TClass * GetClassPointer() const
Returns a pointer to the TClass of this element.
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition: TObject.cxx:901
const Bool_t kIterBackward
Definition: TCollection.h:38
virtual void Compress()
Remove empty slots from array.
Definition: TObjArray.cxx:309
virtual const char * GetName() const
Returns name of object.
Definition: TObject.cxx:364
virtual Int_t GetSize() const
Definition: TCollection.h:89
Abstract Interface class describing Streamer information for one class.
virtual const char * GetName() const
Returns name of object.
Definition: TRealData.h:52
Int_t GetNumber() const
TVirtualStreamerInfo * FindStreamerInfoAbstractEmulated(UInt_t checksum) const
For the case where the requestor class is emulated and this class is abstract, returns a pointer to t...
Definition: TClass.cxx:4503
TClass * GetClass() const
Definition: TDataMember.h:71
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
Definition: TNamed.cxx:155
Int_t GetOffset() const
Bool_t IsaPointer() const
Return true if data member is a pointer.
const Bool_t kTRUE
Definition: RtypesCore.h:91
static UInt_t GenerateClassPrefix(FILE *fp, const char *clname, Bool_t top, TString &protoname, UInt_t *numberOfClasses, Int_t implementEmptyClass=kFALSE, Bool_t needGenericTemplate=kFALSE)
Write the start of the class (forward) declaration.
Int_t GetType() const
void CopyCollectionProxy(const TVirtualCollectionProxy &)
Copy the argument.
Definition: TClass.cxx:2390
void SetReadRawFunc(ROOT::TSchemaRule::ReadRawFuncPtr_t val)
Bool_t IsObject() const
Definition: TRealData.h:56
TRealData * GetRealData(const char *name) const
Return pointer to TRealData element with name "name".
Definition: TClass.cxx:3279
const char * cnt
Definition: TXMLSetup.cxx:75
TObject * Clone(const char *newname="") const
Make a clone of an object using the Streamer facility.
Bool_t CompareContent(TClass *cl, TVirtualStreamerInfo *info, Bool_t warn, Bool_t complete, TFile *file)
Return True if the current StreamerInfo in cl or info is equivalent to this TStreamerInfo.
std::atomic< ULong_t > fLiveCount
! Number of outstanding pointer to this StreamerInfo.
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition: TObject.cxx:859
virtual Version_t ReadVersion(UInt_t *start=0, UInt_t *bcnt=0, const TClass *cl=0)=0
void Resize(Ssiz_t n)
Resize the string. Truncate or add blanks as necessary.
Definition: TString.cxx:1069
static TClassStreamer * GenExplicitClassStreamer(const ::ROOT::TCollectionProxyInfo &info, TClass *cl)
Generate class streamer from static functions.
TStreamerInfo()
Default ctor.
virtual const char * GetTitle() const
Returns title of object.
Definition: TNamed.h:48
This class stores the date and time with a precision of one second in an unsigned 32 bit word (950130...
Definition: TDatime.h:37
TClass * GetClass() const
static void R__TObjArray_InsertAfter(TObjArray *arr, TObject *newobj, TObject *oldobj)
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition: TClass.cxx:4706
const char * Data() const
Definition: TString.h:347
Array of chars or bytes (8 bits per element).
Definition: TArrayC.h:27
EReadWrite
EReadWrite Enumerator Enum Constant Description kBase Base class element kOffsetL Fixed size array k...