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