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