Logo ROOT   6.08/07
Reference Guide
TStreamerInfo.cxx
Go to the documentation of this file.
1 // @(#)root/io:$Id$
2 // Author: Rene Brun 12/10/2000
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 /**
13 \class TStreamerInfo TStreamerInfo.cxx
14 \ingroup IO
15 
16 Describes a persistent version of a class.
17 
18 A ROOT file contains the list of TStreamerInfo objects for all the
19 class versions written to this file.
20 When reading a file, all the TStreamerInfo objects are read back in
21 memory and registered to the TClass list of TStreamerInfo.
22 One can see the list and contents of the TStreamerInfo on a file
23 with, e.g.,
24 ~~~{.cpp}
25  TFile f("myfile.root");
26  f.ShowStreamerInfo();
27 ~~~
28 A TStreamerInfo is a list of TStreamerElement objects (one per data
29 member or base class).
30 When streaming an object, the system (TClass) loops on all the
31 TStreamerElement objects and calls the appropriate function for each
32 element type.
33 */
34 
35 #include "TStreamerInfo.h"
36 #include "TFile.h"
37 #include "TROOT.h"
38 #include "TClonesArray.h"
39 #include "TStreamerElement.h"
40 #include "TClass.h"
41 #include "TClassEdit.h"
42 #include "TDataMember.h"
43 #include "TMethodCall.h"
44 #include "TDataType.h"
45 #include "TRealData.h"
46 #include "TBaseClass.h"
47 #include "TBuffer.h"
48 #include "TArrayC.h"
49 #include "TArrayI.h"
50 #include "TArrayF.h"
51 #include "TArrayD.h"
52 #include "TArrayS.h"
53 #include "TArrayL.h"
54 #include "TError.h"
55 #include "TRef.h"
56 #include "TProcessID.h"
57 #include "TSystem.h"
58 
59 #include "TStreamer.h"
60 #include "TContainerConverters.h"
63 #include "TInterpreter.h"
64 
65 #include "TMemberInspector.h"
66 
67 #include "TMakeProject.h"
68 
69 #include "TSchemaRuleSet.h"
70 #include "TSchemaRule.h"
71 
72 #include "TVirtualMutex.h"
73 
74 #include "TStreamerInfoActions.h"
75 
76 #include <memory>
77 #include <array>
78 
79 std::atomic<Int_t> TStreamerInfo::fgCount{0};
80 
81 const Int_t kMaxLen = 1024;
82 
84 
85 static void R__TObjArray_InsertAt(TObjArray *arr, TObject *obj, Int_t at)
86 {
87  // Slide by one.
88  Int_t last = arr->GetLast();
89  arr->AddAtAndExpand(arr->At(last),last+1);
90  for(Int_t ind = last-1; ind >= at; --ind) {
91  arr->AddAt( arr->At(ind), ind+1);
92  };
93  arr->AddAt( obj, at);
94 }
95 
96 static void R__TObjArray_InsertAt(TObjArray *arr, std::vector<TStreamerArtificial*> &objs, Int_t at)
97 {
98  // Slide by enough.
99  Int_t offset = objs.size();
100  Int_t last = arr->GetLast();
101  arr->AddAtAndExpand(arr->At(last),last+offset);
102  for(Int_t ind = last-1; ind >= at; --ind) {
103  arr->AddAt( arr->At(ind), ind+offset);
104  };
105  for(size_t ins = 0; ins < objs.size(); ++ins) {
106  arr->AddAt(objs[ins], at+ins);
107  }
108 }
109 
110 static void R__TObjArray_InsertAfter(TObjArray *arr, TObject *newobj, TObject *oldobj)
111 {
112  // Slide by one.
113  Int_t last = arr->GetLast();
114  Int_t at = 0;
115  while (at<last && arr->At(at) != oldobj) {
116  ++at;
117  }
118  ++at; // we found the object, insert after it
119  R__TObjArray_InsertAt(arr, newobj, at);
120 }
121 
122 static void R__TObjArray_InsertBefore(TObjArray *arr, TObject *newobj, TObject *oldobj)
123 {
124  // Slide by one.
125  Int_t last = arr->GetLast();
126  Int_t at = 0;
127  while (at<last && arr->At(at) != oldobj) {
128  ++at;
129  }
130  R__TObjArray_InsertAt(arr, newobj, at);
131 }
132 
133 enum class EUniquePtrOffset : char
134  {
135  kNA = 0,
136  kZero = 1,
137  kNonZero = 2
138  };
139 
140 ////////////////////////////////////////////////////////////////////////////////
141 /// Default ctor.
142 
144 {
145  fNumber = fgCount;
146  fClass = 0;
147  fElements = 0;
148  fComp = 0;
149  fCompFull = 0;
150  fCompOpt = 0;
151  fCheckSum = 0;
152  fNdata = 0;
153  fNfulldata= 0;
154  fNslots = 0;
155  fSize = 0;
156  fClassVersion = 0;
157  fOnFileClassVersion = 0;
158  fOldVersion = Class()->GetClassVersion();
159  fNVirtualInfoLoc = 0;
160  fVirtualInfoLoc = 0;
161  fLiveCount = 0;
162 
163  fReadObjectWise = 0;
164  fReadMemberWise = 0;
165  fReadMemberWiseVecPtr = 0;
166  fWriteObjectWise = 0;
167  fWriteMemberWise = 0;
168  fWriteMemberWiseVecPtr = 0;
169 }
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  constexpr size_t kSizeOfPtr = 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  } // if element is of type TStreamerBase or not.
1971  } // if (element->IsBase())
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  } // Class corresponding to StreamerInfo is emulated or not.
2073 
2074  // Now let's deal with Schema evolution
2075  Int_t newType = -1;
2076  TClassRef newClass;
2077 
2078  if (dm && dm->IsPersistent()) {
2079  auto theType = isStdArray ? dt : dm->GetDataType();
2080  if (theType) {
2081  Bool_t isArray = isStdArray || element->GetArrayLength() >= 1;
2082  Bool_t hasCount = element->HasCounter();
2083  // data member is a basic type
2084  if ((fClass == TObject::Class()) && !strcmp(dm->GetName(), "fBits")) {
2085  //printf("found fBits, changing dtype from %d to 15\n", dtype);
2086  newType = kBits;
2087  } else {
2088  // All the values of EDataType have the same semantic in EReadWrite
2089  newType = (EReadWrite)theType->GetType();
2090  }
2091  if ((newType == ::kChar_t) && dmIsPtr && !isArray && !hasCount) {
2092  newType = ::kCharStar;
2093  } else if (dmIsPtr) {
2094  newType += kOffsetP;
2095  } else if (isArray) {
2096  newType += kOffsetL;
2097  }
2098  }
2099  if (newType == -1) {
2100  newClass = TClass::GetClass(dmType);
2101  }
2102  } else {
2103  // Either the class is not loaded or the data member is gone
2104  if (!fClass->IsLoaded()) {
2106  if (newInfo && (newInfo != this)) {
2107  TStreamerElement* newElems = (TStreamerElement*) newInfo->GetElements()->FindObject(element->GetName());
2108  newClass = newElems ? newElems->GetClassPointer() : 0;
2109  if (newClass == 0) {
2110  newType = newElems ? newElems->GetType() : -1;
2111  if (!(newType < kObject)) {
2112  // sanity check.
2113  newType = -1;
2114  }
2115  }
2116  } else {
2117  newClass = element->GetClassPointer();
2118  if (newClass.GetClass() == 0) {
2119  newType = element->GetType();
2120  if (!(newType < kObject)) {
2121  // sanity check.
2122  newType = -1;
2123  }
2124  }
2125  }
2126  }
2127  }
2128 
2129  if (newType > 0) {
2130  // Case of a numerical type
2131  if (element->GetType() >= TStreamerInfo::kObject) {
2132  // Old type was not a numerical type.
2133  element->SetNewType(-2);
2134  } else if (element->GetType() != newType) {
2135  element->SetNewType(newType);
2136  if (gDebug > 0) {
2137  // coverity[mixed_enums] - All the values of EDataType have the same semantic in EReadWrite
2138  Info("BuildOld", "element: %s %s::%s has new type: %s/%d", element->GetTypeName(), GetName(), element->GetName(), dm ? dm->GetFullTypeName() : TDataType::GetTypeName((EDataType)newType), newType);
2139  }
2140  }
2141  } else if (newClass.GetClass()) {
2142  // Sometime BuildOld is called again.
2143  // In that case we might already have fix up the streamer element.
2144  // So we need to go back to the original information!
2145  newClass.Reset();
2147  if (oldClass == newClass.GetClass()) {
2148  // Nothing to do, also in the unique_ptr case :)
2149  } else if (ClassWasMovedToNamespace(oldClass, newClass.GetClass())) {
2150  Int_t oldv;
2151  if (0 != (oldv = ImportStreamerInfo(oldClass, newClass.GetClass()))) {
2152  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);
2153  } else {
2154  element->SetTypeName(newClass->GetName());
2155  if (gDebug > 0) {
2156  Warning("BuildOld", "element: %s::%s %s has new type %s", GetName(), element->GetTypeName(), element->GetName(), newClass->GetName());
2157  }
2158  }
2159  } else if (oldClass == TClonesArray::Class()) {
2160  if (ContainerMatchTClonesArray(newClass.GetClass())) {
2161  Int_t elemType = element->GetType();
2162  Bool_t isPrealloc = (elemType == kObjectp) || (elemType == kAnyp) || (elemType == (kObjectp + kOffsetL)) || (elemType == (kAnyp + kOffsetL));
2163  element->Update(oldClass, newClass.GetClass());
2164  TVirtualCollectionProxy *cp = newClass->GetCollectionProxy();
2165  TConvertClonesArrayToProxy *ms = new TConvertClonesArrayToProxy(cp, element->IsaPointer(), isPrealloc);
2166  element->SetStreamer(ms);
2167 
2168  // When the type is kObject, the TObject::Streamer is used instead
2169  // of the TStreamerElement's streamer. So let force the usage
2170  // of our streamer
2171  if (element->GetType() == kObject) {
2172  element->SetNewType(kAny);
2173  element->SetType(kAny);
2174  }
2175  if (gDebug > 0) {
2176  Warning("BuildOld","element: %s::%s %s has new type %s", GetName(), element->GetTypeName(), element->GetName(), newClass->GetName());
2177  }
2178  } else {
2179  element->SetNewType(-2);
2180  }
2181  } else if (oldClass && oldClass->GetCollectionProxy() && newClass->GetCollectionProxy()) {
2182  {
2183  TClass *oldFixedClass = FixCollectionV5(GetClass(),oldClass,newClass);
2184  if (oldFixedClass && oldFixedClass != oldClass) {
2185  element->Update(oldClass,oldFixedClass);
2186  oldClass = oldFixedClass;
2187  }
2188  }
2189  if (CollectionMatch(oldClass, newClass)) {
2190  Int_t oldkind = oldClass->GetCollectionType();
2191  Int_t newkind = newClass->GetCollectionType();
2192 
2193  if ( (oldkind==ROOT::kSTLmap || oldkind==ROOT::kSTLmultimap) &&
2194  (newkind!=ROOT::kSTLmap && newkind!=ROOT::kSTLmultimap) ) {
2195 
2196  Int_t elemType = element->GetType();
2197  Bool_t isPrealloc = (elemType == kObjectp) || (elemType == kAnyp) || (elemType == (kObjectp + kOffsetL)) || (elemType == (kAnyp + kOffsetL));
2198 
2199  TClassStreamer *streamer2 = newClass->GetStreamer();
2200  if (streamer2) {
2201  TConvertMapToProxy *ms = new TConvertMapToProxy(streamer2, element->IsaPointer(), isPrealloc);
2202  if (ms && ms->IsValid()) {
2203  element->SetStreamer(ms);
2204  switch( element->GetType() ) {
2205  //case TStreamerInfo::kSTLvarp: // Variable size array of STL containers.
2206  case TStreamerInfo::kSTLp: // Pointer to container with no virtual table (stl) and no comment
2207  case TStreamerInfo::kSTLp + TStreamerInfo::kOffsetL: // array of pointers to container with no virtual table (stl) and no comment
2208  element->SetNewType(-2);
2209  break;
2210  case TStreamerInfo::kSTL: // container with no virtual table (stl) and no comment
2211  case TStreamerInfo::kSTL + TStreamerInfo::kOffsetL: // array of containers with no virtual table (stl) and no comment
2212  break;
2213  }
2214  } else {
2215  delete ms;
2216  }
2217  }
2218  element->Update(oldClass, newClass.GetClass());
2219 
2220  } else if ( (newkind==ROOT::kSTLmap || newkind==ROOT::kSTLmultimap) &&
2221  (oldkind!=ROOT::kSTLmap && oldkind!=ROOT::kSTLmultimap) ) {
2222  element->SetNewType(-2);
2223  } else {
2224  element->Update(oldClass, newClass.GetClass());
2225  }
2226  // Is this needed ? : element->SetSTLtype(newelement->GetSTLtype());
2227  if (gDebug > 0) {
2228  Warning("BuildOld","element: %s::%s %s has new type %s", GetName(), element->GetTypeName(), element->GetName(), newClass->GetName());
2229  }
2230  } else if (CollectionMatchFloat16(oldClass,newClass)) {
2231  // Actually nothing to do, since both are the same collection of double in memory.
2232  } else if (CollectionMatchDouble32(oldClass,newClass)) {
2233  // Actually nothing to do, since both are the same collection of double in memory.
2234  } else if (CollectionMatchLong64(oldClass,newClass)) {
2235  // Not much to do since both are the same collection of 8 bits entities on file.
2236  element->Update(oldClass, newClass.GetClass());
2237  } else if (CollectionMatchULong64(oldClass,newClass)) {
2238  // Not much to do since both are the same collection of 8 bits unsigned entities on file
2239  element->Update(oldClass, newClass.GetClass());
2240  } else if (newClass->GetSchemaRules()->HasRuleWithSourceClass( oldClass->GetName() )) {
2241  //------------------------------------------------------------------------
2242  // We can convert one type to another (at least for some of the versions).
2243  /////////////////////////////////////////////////////////////////
2244 
2245  element->SetNewClass( newClass );
2246  } else {
2247  element->SetNewType(-2);
2248  }
2249 
2250  } else if(oldClass &&
2251  newClass.GetClass() &&
2252  newClass->GetSchemaRules() &&
2253  newClass->GetSchemaRules()->HasRuleWithSourceClass( oldClass->GetName() ) ) {
2254  //------------------------------------------------------------------------
2255  // We can convert one type to another (at least for some of the versions).
2256  ////////////////////////////////////////////////////////////////////
2257 
2258  element->SetNewClass( newClass );
2259  } else {
2260  element->SetNewType(-2);
2261  }
2262  // Humm we still need to make sure we have the same 'type' (pointer, embedded object, array, etc..)
2263  Bool_t cannotConvert = kFALSE;
2264  if (element->GetNewType() != -2) {
2265  if (dm) {
2266  if (dmIsPtr) {
2267  if (isUniquePtr || strncmp(dm->GetTitle(),"->",2)==0) {
2268  // We are fine, nothing to do.
2269  if (newClass->IsTObject()) {
2270  newType = kObjectp;
2271  } else if (newClass->GetCollectionProxy()) {
2272  newType = kSTLp;
2273  } else {
2274  newType = kAnyp;
2275  }
2276  } else {
2277  if (TClass::GetClass(dm->GetTypeName())->IsTObject()) {
2278  newType = kObjectP;
2279  } else if (newClass->GetCollectionProxy()) {
2280  newType = kSTLp;
2281  } else {
2282  newType = kAnyP;
2283  }
2284  }
2285  } else {
2286  if (newClass->GetCollectionProxy()) {
2287  newType = kSTL;
2288  } else if (newClass == TString::Class()) {
2289  newType = kTString;
2290  } else if (newClass == TObject::Class()) {
2291  newType = kTObject;
2292  } else if (newClass == TNamed::Class()) {
2293  newType = kTNamed;
2294  } else if (newClass->IsTObject()) {
2295  newType = kObject;
2296  } else {
2297  newType = kAny;
2298  }
2299  }
2300  if ((!dmIsPtr || newType==kSTLp) && (isStdArray ? ndim : dm->GetArrayDim()) > 0) {
2301  newType += kOffsetL;
2302  }
2303  } else if (!fClass->IsLoaded()) {
2305  if (newInfo && (newInfo != this)) {
2306  TStreamerElement* newElems = (TStreamerElement*) newInfo->GetElements()->FindObject(element->GetName());
2307  if (newElems) {
2308  newType = newElems->GetType();
2309  }
2310  } else {
2311  newType = element->GetType();
2312  }
2313  }
2314  if (element->GetType() == kSTL
2315  || ((element->GetType() == kObject || element->GetType() == kAny || element->GetType() == kObjectp || element->GetType() == kAnyp)
2316  && oldClass == TClonesArray::Class()))
2317  {
2318  cannotConvert = (newType != kSTL && newType != kObject && newType != kAny && newType != kSTLp && newType != kObjectp && newType != kAnyp);
2319 
2320  } else if (element->GetType() == kSTLp || ((element->GetType() == kObjectP || element->GetType() == kAnyP) && oldClass == TClonesArray::Class()) )
2321  {
2322  cannotConvert = (newType != kSTL && newType != kObject && newType != kAny && newType != kSTLp && newType != kObjectP && newType != kAnyP);
2323 
2324  } else if (element->GetType() == kSTL + kOffsetL
2325  || ((element->GetType() == kObject + kOffsetL|| element->GetType() == kAny + kOffsetL|| element->GetType() == kObjectp+ kOffsetL || element->GetType() == kAnyp+ kOffsetL)
2326  && oldClass == TClonesArray::Class()))
2327  {
2328  cannotConvert = (newType != kSTL + kOffsetL && newType != kObject+ kOffsetL && newType != kAny+ kOffsetL && newType != kSTLp+ kOffsetL && newType != kObjectp+ kOffsetL && newType != kAnyp+ kOffsetL);
2329 
2330  } else if (element->GetType() == kSTLp + kOffsetL || ((element->GetType() == kObjectP+ kOffsetL || element->GetType() == kAnyP+ kOffsetL) && oldClass == TClonesArray::Class()) )
2331  {
2332  cannotConvert = (newType != kSTL+ kOffsetL && newType != kObject+ kOffsetL && newType != kAny+ kOffsetL && newType != kSTLp + kOffsetL&& newType != kObjectP+ kOffsetL && newType != kAnyP+ kOffsetL);
2333 
2334  } else if ((element->GetType() == kObjectp || element->GetType() == kAnyp
2335  || element->GetType() == kObject || element->GetType() == kAny
2336  || element->GetType() == kTObject || element->GetType() == kTNamed || element->GetType() == kTString )) {
2337  // We had Type* ... ; //-> or Type ...;
2338  // this is completely compatible with the same and with a embedded object.
2339  if (newType != -1) {
2340  if (newType == kObjectp || newType == kAnyp
2341  || newType == kObject || newType == kAny
2342  || newType == kTObject || newType == kTNamed || newType == kTString) {
2343  // We are fine, no transformation to make
2344  element->SetNewType(newType);
2345  } else {
2346  // We do not support this yet.
2347  cannotConvert = kTRUE;
2348  }
2349  } else {
2350  // We have no clue
2351  printf("%s We have no clue\n", dm->GetName());
2352  cannotConvert = kTRUE;
2353  }
2354  } else if (element->GetType() == kObjectP || element->GetType() == kAnyP) {
2355  if (newType != -1) {
2356  if (newType == kObjectP || newType == kAnyP ) {
2357  // nothing to do}
2358  } else {
2359  cannotConvert = kTRUE;
2360  }
2361  } else {
2362  // We have no clue
2363  cannotConvert = kTRUE;
2364  }
2365  }
2366  }
2367  if (cannotConvert) {
2368  element->SetNewType(-2);
2369  if (gDebug > 0) {
2370  // coverity[mixed_enums] - All the values of EDataType have the same semantic in EReadWrite
2371  Info("BuildOld", "element: %s %s::%s has new type: %s/%d", element->GetTypeName(), GetName(), element->GetName(), dm ? dm->GetFullTypeName() : TDataType::GetTypeName((EDataType)newType), newType);
2372  }
2373  }
2374  } else {
2375  element->SetNewType(-1);
2376  offset = kMissing;
2377  element->SetOffset(kMissing);
2378  }
2379 
2380  if (offset != kMissing && fClass->GetState() <= TClass::kEmulated) {
2381  // Note the initialization in this case are
2382  // delayed until __after__ the schema evolution
2383  // section, just in case the info has changed.
2384 
2385  // The class is NOT known to Cling, i.e. is emulated,
2386  // and we need to use the calculated offset.
2387 
2388  Int_t asize;
2389  if (element->GetType() == TStreamerInfo::kSTL &&
2390  strcmp(element->GetName(),"This") == 0 &&
2391  strcmp(element->GetTypeName(),GetName()) == 0 &&
2392  !fClass->GetCollectionProxy()) {
2393  // Humm .. we are missing the collection Proxy
2394  // for a proxied (custom) collection ... avoid
2395  // an infinite recursion and take a wild guess
2396  asize = sizeof(std::vector<int>);
2397  } else {
2398  // Regular case
2399  asize = element->GetSize();
2400  }
2401  // align the non-basic data types (required on alpha and IRIX!!)
2402  if ((offset % kSizeOfPtr) != 0) {
2403  offset = offset - (offset % kSizeOfPtr) + kSizeOfPtr;
2404  }
2405  element->SetOffset(offset);
2406  offset += asize;
2407  }
2408 
2409  if (!wasCompiled && rules) {
2410  if (rules.HasRuleWithSource( element->GetName(), kTRUE ) ) {
2411 
2412  if (allocClass == 0) {
2413  infoalloc = (TStreamerInfo *)Clone(TString::Format("%s@@%d",GetName(),GetOnFileClassVersion()));
2414  if (!infoalloc) {
2415  Error("BuildOld","Unable to create the StreamerInfo for %s.",TString::Format("%s@@%d",GetName(),GetOnFileClassVersion()).Data());
2416  } else {
2417  infoalloc->SetBit(kBuildOldUsed,false);
2418  infoalloc->BuildCheck();
2419  infoalloc->BuildOld();
2420  allocClass = infoalloc->GetClass();
2421  }
2422  }
2423 
2424  // Now that we are caching the unconverted element, we do not assign it to the real type even if we could have!
2425  if (element->GetNewType()>0 /* intentionally not including base class for now */
2426  && !rules.HasRuleWithTarget( element->GetName(), kTRUE ) ) {
2427 
2428  TStreamerElement *copy = (TStreamerElement*)element->Clone();
2429  R__TObjArray_InsertBefore( fElements, copy, element );
2430  next(); // move the cursor passed the insert object.
2432  element = copy;
2433 
2434  // 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() );
2435  } else {
2436  // If the element is just cached and not repeat, we need to inject an element
2437  // to insure the writing.
2438  TStreamerElement *writecopy = (TStreamerElement*)element->Clone();
2439  R__TObjArray_InsertAfter( fElements, writecopy, element );
2440  next(); // move the cursor passed the insert object.
2441  writecopy->SetBit(TStreamerElement::kWrite);
2442  writecopy->SetNewType( writecopy->GetType() );
2443  writecopy->SetBit(TStreamerElement::kCache);
2444  writecopy->SetOffset(infoalloc ? infoalloc->GetOffset(element->GetName()) : 0);
2445  }
2446  element->SetBit(TStreamerElement::kCache);
2447  element->SetNewType( element->GetType() );
2448  element->SetOffset(infoalloc ? infoalloc->GetOffset(element->GetName()) : 0);
2449  } else if (rules.HasRuleWithTarget( element->GetName(), kTRUE ) ) {
2450  // The data member exist in the onfile StreamerInfo and there is a rule
2451  // that has the same member 'only' has a target ... so this means we are
2452  // asked to ignore the input data ...
2453  if (element->GetType() == kCounter) {
2454  // If the element is a counter, we will need its value to read
2455  // other data member, so let's do so (by not disabling it) even
2456  // if the value will be over-written by a rule.
2457  } else {
2458  element->SetOffset(kMissing);
2459  }
2460  }
2461  } else if (rules && rules.HasRuleWithTarget( element->GetName(), kTRUE ) ) {
2462  // The data member exist in the onfile StreamerInfo and there is a rule
2463  // that has the same member 'only' has a target ... so this means we are
2464  // asked to ignore the input data ...
2465  if (element->GetType() == kCounter) {
2466  // If the element is a counter, we will need its value to read
2467  // other data member, so let's do so (by not disabling it) even
2468  // if the value will be over-written by a rule.
2469  } else {
2470  element->SetOffset(kMissing);
2471  }
2472  }
2473 
2474  if (element->GetNewType() == -2) {
2475  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") );
2476  }
2477  }
2478 
2479  // If we get here, this means that there no data member after the last base class
2480  // (or no base class at all).
2481  if (shouldHaveInfoLoc && fNVirtualInfoLoc==0) {
2482  fNVirtualInfoLoc = 1;
2483  fVirtualInfoLoc = new ULong_t[1]; // To allow for a single delete statement.
2484  fVirtualInfoLoc[0] = offset;
2485  offset += sizeof(TStreamerInfo*);
2486  }
2487 
2488  // change order , move "bazes" to the end. Workaround old bug
2489  if ((fOldVersion <= 2) && nBaze) {
2490  SetBit(kRecovered);
2491  TObjArray& arr = *fElements;
2492  TObjArray tai(nBaze);
2493  int narr = arr.GetLast() + 1;
2494  int iel;
2495  int jel = 0;
2496  int kel = 0;
2497  for (iel = 0; iel < narr; ++iel) {
2498  element = (TStreamerElement*) arr[iel];
2499  if (element->IsBase() && (element->IsA() != TStreamerBase::Class())) {
2500  tai[kel++] = element;
2501  } else {
2502  arr[jel++] = element;
2503  }
2504  }
2505  for (kel = 0; jel < narr;) {
2506  arr[jel++] = tai[kel++];
2507  }
2508  }
2509 
2510  // Now add artificial TStreamerElement (i.e. rules that creates new members or set transient members).
2511  if (!wasCompiled) InsertArtificialElements(rules);
2512 
2513  if (!wasCompiled && allocClass) {
2514 
2515  TStreamerElement *el = new TStreamerArtificial("@@alloc","", 0, TStreamerInfo::kCacheNew, allocClass->GetName());
2516  R__TObjArray_InsertAt( fElements, el, 0 );
2517 
2518  el = new TStreamerArtificial("@@dealloc","", 0, TStreamerInfo::kCacheDelete, allocClass->GetName());
2519  fElements->Add( el );
2520  }
2521 
2522  Compile();
2523 }
2524 
2525 ////////////////////////////////////////////////////////////////////////////////
2526 /// If opt contains 'built', reset this StreamerInfo as if Build or BuildOld
2527 /// was never called on it (useful to force their re-running).
2528 
2530 {
2531  TString opt = option;
2532  opt.ToLower();
2533 
2534  if (opt.Contains("build")) {
2536 
2537  delete [] fComp; fComp = 0;
2538  delete [] fCompFull; fCompFull= 0;
2539  delete [] fCompOpt; fCompOpt = 0;
2540  fNdata = 0;
2541  fNfulldata = 0;
2542  fNslots= 0;
2543  fSize = 0;
2544  ResetIsCompiled();
2546 
2553  }
2554 }
2555 
2556 namespace {
2557  // TMemberInfo
2558  // Local helper class to be able to compare data member represented by
2559  // 2 distinct TStreamerInfos
2560  class TMemberInfo {
2561  public:
2562  TClass *fParent;
2563  TString fName;
2564  TString fClassName;
2565  TString fComment;
2566  Int_t fDataType;
2567 
2568  TMemberInfo(TClass *parent) : fParent(parent) {};
2569 
2570  void SetDataType(Int_t datatype) {
2571  fDataType = datatype;
2572  }
2573 
2574  void SetName(const char *name) {
2575  fName = name;
2576  }
2577  void SetClassName(const char *name) {
2579  }
2580  void SetComment(const char *title) {
2581  const char *left = strstr(title,"[");
2582  if (left) {
2583  const char *right = strstr(left,"]");
2584  if (right) {
2585  ++left;
2586  fComment.Append(left,right-left);
2587  }
2588  }
2589  }
2590  void Clear() {
2591  fName.Clear();
2592  fClassName.Clear();
2593  fComment.Clear();
2594  }
2595  /* Hide this not yet used implementation to suppress warnings message
2596  from icc 11
2597  Bool_t operator==(const TMemberInfo &other) {
2598  return fName==other.fName
2599  && fClassName == other.fClassName
2600  && fComment == other.fComment;
2601  }
2602  */
2603  Bool_t operator!=(const TMemberInfo &other) {
2604  if (fName != other.fName) return kTRUE;
2605  if (fDataType < TStreamerInfo::kObject) {
2606  // For simple type, let compare the data type
2607  if (fDataType != other.fDataType) {
2608  if ( (fDataType == 4 && other.fDataType == 16)
2609  || (fDataType == 16 && other.fDataType == 4) ) {
2610  // long and 'long long' have the same file format
2611  } else if ( (fDataType == 14 && other.fDataType == 17)
2612  || (fDataType == 17 && other.fDataType == 14) ) {
2613  // unsigned long and 'unsigned long long' have the same file format
2614  } else if ( (fDataType == 3 && other.fDataType == 6)
2615  ||(fDataType == 6 && other.fDataType == 3) ){
2616  // Int_t and kCounter. As the switch from Int_t (3) to
2617  // kCounter (6) might be triggered by a derived class using
2618  // the field as an array size, the class itself has no
2619  // control on what the field type really use.
2620  } else {
2621  return kTRUE;
2622  }
2623  }
2624  } else if (fClassName != other.fClassName) {
2625  if ( (fClassName == "long" && (other.fClassName == "long long" || other.fClassName == "Long64_t"))
2626  || ( (fClassName == "long long" || fClassName == "Long64_t") && other.fClassName == "long") ) {
2627  // This is okay both have the same on file format.
2628  } else if ( (fClassName == "unsigned long" && (other.fClassName == "unsigned long long" || other.fClassName == "ULong64_t"))
2629  || ( (fClassName == "unsigned long long" || fClassName == "ULong64_t") && other.fClassName == "unsigned long") ) {
2630  // This is okay both have the same on file format.
2631  } else if (TClassEdit::IsSTLCont(fClassName)) {
2633  TString othername = TClassEdit::ShortType( other.fClassName, TClassEdit::kDropStlDefault );
2634  if (name != othername) {
2635  TClass *cl = TClass::GetClass(name);
2636  TClass *otherCl = TClass::GetClass(othername);
2637  if (!CollectionMatch(cl,otherCl)) {
2638  TClass *oldFixedClass = FixCollectionV5(fParent,cl,otherCl);
2639  if (!oldFixedClass || !CollectionMatch(oldFixedClass,otherCl)) {
2640  return kTRUE;
2641  }
2642  }
2643  }
2644  } else {
2645  return kTRUE;
2646  }
2647  }
2648  return fComment != other.fComment;
2649  }
2650  };
2651 }
2652 
2653 ////////////////////////////////////////////////////////////////////////////////
2654 /// Emulated a call ShowMembers() on the obj of this class type, passing insp and parent.
2655 
2656 void TStreamerInfo::CallShowMembers(const void* obj, TMemberInspector &insp, Bool_t isTransient) const
2657 {
2658  TIter next(fElements);
2659  TStreamerElement* element = (TStreamerElement*) next();
2660 
2661  TString elementName;
2662 
2663  for (; element; element = (TStreamerElement*) next()) {
2664 
2665  // Skip elements which have not been allocated memory.
2666  if (element->GetOffset() == kMissing) {
2667  continue;
2668  }
2669 
2670  char* eaddr = ((char*)obj) + element->GetOffset();
2671 
2672  if (element->IsBase()) {
2673  // Nothing to do this round.
2674  } else if (element->IsaPointer()) {
2675  elementName.Form("*%s",element->GetFullName());
2676  insp.Inspect(fClass, insp.GetParent(), elementName.Data(), eaddr, isTransient);
2677  } else {
2678  insp.Inspect(fClass, insp.GetParent(), element->GetFullName(), eaddr, isTransient);
2679  Int_t etype = element->GetType();
2680  switch(etype) {
2681  case kObject:
2682  case kAny:
2683  case kTObject:
2684  case kTString:
2685  case kTNamed:
2686  case kSTL:
2687  {
2688  TClass *ecl = element->GetClassPointer();
2689  if (ecl && (fClass!=ecl /* This happens 'artificially for stl container see the use of "This" */)) {
2690  insp.InspectMember(ecl, eaddr, TString(element->GetName()) + ".", isTransient);
2691  }
2692  break;
2693  }
2694  } // switch(etype)
2695  } // if IsaPointer()
2696  } // Loop over elements
2697 
2698  // And now do the base classes
2699  next.Reset();
2700  element = (TStreamerElement*) next();
2701  for (; element; element = (TStreamerElement*) next()) {
2702  if (element->IsBase()) {
2703  // Skip elements which have not been allocated memory.
2704  if (element->GetOffset() == kMissing) {
2705  continue;
2706  }
2707 
2708  char* eaddr = ((char*)obj) + element->GetOffset();
2709 
2710  TClass *ecl = element->GetClassPointer();
2711  if (ecl) {
2712  ecl->CallShowMembers(eaddr, insp, isTransient);
2713  }
2714  } // If is a abse
2715  } // Loop over elements
2716 }
2717 
2718 ////////////////////////////////////////////////////////////////////////////////
2719 /// Make a clone of an object using the Streamer facility.
2720 /// If newname is specified, this will be the name of the new object.
2721 
2722 TObject *TStreamerInfo::Clone(const char *newname) const
2723 {
2724  TStreamerInfo *newinfo = (TStreamerInfo*)TNamed::Clone(newname);
2725  if (newname && newname[0] && fName != newname) {
2726  TObjArray *newelems = newinfo->GetElements();
2727  Int_t ndata = newelems->GetEntries();
2728  for(Int_t i = 0; i < ndata; ++i) {
2729  TObject *element = newelems->UncheckedAt(i);
2730  if (element->IsA() == TStreamerLoop::Class()) {
2731  TStreamerLoop *eloop = (TStreamerLoop*)element;
2732  if (fName == eloop->GetCountClass()) {
2733  eloop->SetCountClass(newname);
2734  eloop->Init();
2735  }
2736  } else if (element->IsA() == TStreamerBasicPointer::Class()) {
2737  TStreamerBasicPointer *eptr = (TStreamerBasicPointer*)element;
2738  if (fName == eptr->GetCountClass()) {
2739  eptr->SetCountClass(newname);
2740  eptr->Init();
2741  }
2742  }
2743  }
2744  }
2745  return newinfo;
2746 }
2747 
2748 ////////////////////////////////////////////////////////////////////////////////
2749 /// Return True if the current StreamerInfo in cl or info is equivalent to this TStreamerInfo.
2750 ///
2751 /// In this context 'Equivalent' means the same number of persistent data member which the same actual C++ type and
2752 /// the same name.
2753 /// If 'warn' is true, Warning message are printed to explicit the differences.
2754 /// If 'complete' is false, stop at the first error, otherwise continue until all members have been checked.
2755 
2757 {
2758  Bool_t result = kTRUE;
2759  R__ASSERT( (cl==0 || info==0) && (cl!=0 || info!=0) /* must compare to only one thing! */);
2760 
2761  TString name;
2762  TString type;
2763  TStreamerElement *el;
2764  TStreamerElement *infoel = 0;
2765 
2766  TIter next(GetElements());
2767  TIter infonext((TList*)0);
2768  TIter basenext((TList*)0);
2769  TIter membernext((TList*)0);
2770  if (info) {
2771  infonext = info->GetElements();
2772  }
2773  if (cl) {
2774  TList *tlb = cl->GetListOfBases();
2775  if (tlb) { // Loop over bases
2776  basenext = tlb;
2777  }
2778  tlb = cl->GetListOfDataMembers();
2779  if (tlb) {
2780  membernext = tlb;
2781  }
2782  }
2783 
2784  // First let's compare base classes
2785  Bool_t done = kFALSE;
2786  TString localClass;
2787  TString otherClass;
2788  while(!done) {
2789  localClass.Clear();
2790  otherClass.Clear();
2791  el = (TStreamerElement*)next();
2792  if (el && el->IsBase()) {
2793  localClass = el->GetName();
2794  } else {
2795  el = 0;
2796  }
2797  if (cl) {
2798  TBaseClass *tbc = (TBaseClass*)basenext();
2799  if (tbc) {
2800  otherClass = tbc->GetName();
2801  } else if (el==0) {
2802  done = kTRUE;
2803  break;
2804  }
2805  } else {
2806  infoel = (TStreamerElement*)infonext();
2807  if (infoel && infoel->IsBase()) {
2808  otherClass = infoel->GetName();
2809  } else if (el==0) {
2810  done = kTRUE;
2811  break;
2812  }
2813  }
2814  if (TClassEdit::IsSTLCont(localClass)) {
2815  localClass = TClassEdit::ShortType( localClass, TClassEdit::kDropStlDefault );
2816  otherClass = TClassEdit::ShortType( otherClass, TClassEdit::kDropStlDefault );
2817  }
2818  // Need to normalize the name
2819  if (localClass != otherClass) {
2820  if (warn) {
2821  if (el==0) {
2822  Warning("CompareContent",
2823  "The in-memory layout version %d for class '%s' has a base class (%s) that the on-file layout version %d does not have.",
2824  GetClassVersion(), GetName(), otherClass.Data(), GetClassVersion());
2825  } else if (otherClass.Length()==0) {
2826  Warning("CompareContent",
2827  "The on-file layout version %d for class '%s' has a base class (%s) that the in-memory layout version %d does not have",
2828  GetClassVersion(), GetName(), localClass.Data(), GetClassVersion());
2829  } else {
2830  Warning("CompareContent",
2831  "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'",
2832  GetClassVersion(), GetClassVersion(), GetName(), localClass.Data(), otherClass.Data());
2833  }
2834  }
2835  if (!complete) return kFALSE;
2836  result = result && kFALSE;
2837  }
2838  if (cl) {
2839  TStreamerBase *localBase = dynamic_cast<TStreamerBase*>(el);
2840  if (!localBase) continue;
2841  // We already have localBaseClass == otherBaseClass
2842  TClass *otherBaseClass = localBase->GetClassPointer();
2843  if (!otherBaseClass) continue;
2844  if (otherBaseClass->IsVersioned() && localBase->GetBaseVersion() != otherBaseClass->GetClassVersion()) {
2845  TString msg;
2846  msg.Form(" The StreamerInfo of class %s read from %s%s\n"
2847  " has the same version (=%d) as the active class but a different checksum.\n"
2848  " You should update the version to ClassDef(%s,%d).\n"
2849  " The objects on this file might not be readable because:\n"
2850  " 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).",
2851  GetName(), file ? "file " : "", file ? file->GetName() : "", fClassVersion, GetName(), fClassVersion + 1,
2852  GetClassVersion(), GetName(), otherClass.Data(), otherBaseClass->GetClassVersion(),
2853  GetClassVersion(), localBase->GetBaseVersion(), localClass.Data());
2854  TStreamerBase *otherBase = (TStreamerBase*)cl->GetStreamerInfo()->GetElements()->FindObject(otherClass);
2855  otherBase->SetErrorMessage(msg);
2856 
2857  } else if (!otherBaseClass->IsVersioned() && localBase->GetBaseCheckSum() != otherBaseClass->GetCheckSum()) {
2858  TVirtualStreamerInfo *localBaseInfo = otherBaseClass->FindStreamerInfo(localBase->GetBaseCheckSum());
2859  if (!localBaseInfo) {
2860  // We are likely in the situation where the base class comes after the derived
2861  // class in the TFile's list of StreamerInfo, so it has not yet been loaded,
2862  // let's see if it is there.
2863  const TList *list = file->GetStreamerInfoCache();
2864  localBaseInfo = list ? (TStreamerInfo*)list->FindObject(localBase->GetName()) : 0;
2865  }
2866  if (!localBaseInfo) {
2867  TString msg;
2868  msg.Form(" The StreamerInfo of the base class %s (of class %s) read from %s%s\n"
2869  " refers to a checksum (%x) that can not be found neither in memory nor in the file.\n",
2870  otherBaseClass->GetName(), localClass.Data(),
2871  file ? "file " : "", file ? file->GetName() : "",
2872  localBase->GetBaseCheckSum()
2873  );
2874  TStreamerBase *otherBase = (TStreamerBase*)cl->GetStreamerInfo()->GetElements()->FindObject(otherClass);
2875  otherBase->SetErrorMessage(msg);
2876  continue;
2877  }
2878  if (localBaseInfo->CompareContent(otherBaseClass,0,kFALSE,kFALSE,file) ) {
2879  // They are equivalent, no problem.
2880  continue;
2881  }
2882  TString msg;
2883  msg.Form(" The StreamerInfo of class %s read from %s%s\n"
2884  " has the same version (=%d) as the active class but a different checksum.\n"
2885  " You should update the version to ClassDef(%s,%d).\n"
2886  " The objects on this file might not be readable because:\n"
2887  " 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).",
2888  GetName(), file ? "file " : "", file ? file->GetName() : "", fClassVersion, GetName(), fClassVersion + 1,
2889  GetClassVersion(), GetName(), otherClass.Data(), otherBaseClass->GetCheckSum(),
2890  GetClassVersion(), localBase->GetBaseCheckSum(), localClass.Data());
2891  TStreamerBase *otherBase = (TStreamerBase*)cl->GetStreamerInfo()->GetElements()->FindObject(otherClass);
2892  otherBase->SetErrorMessage(msg);
2893  }
2894  } else {
2895  TStreamerBase *localBase = dynamic_cast<TStreamerBase*>(el);
2896  TStreamerBase *otherBase = dynamic_cast<TStreamerBase*>(infoel);
2897  if (!localBase || !otherBase) continue;
2898 
2899  // We already have localBaseClass == otherBaseClass
2900  TClass *otherBaseClass = localBase->GetClassPointer();
2901  if (otherBaseClass->IsVersioned() && localBase->GetBaseVersion() != otherBase->GetBaseVersion()) {
2902  TString msg;
2903  msg.Form(" The StreamerInfo of class %s read from %s%s\n"
2904  " has the same version (=%d) as the active class but a different checksum.\n"
2905  " You should update the version to ClassDef(%s,%d).\n"
2906  " The objects on this file might not be readable because:\n"
2907  " 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).",
2908  GetName(), file ? "file " : "", file ? file->GetName() : "", fClassVersion, GetName(), fClassVersion + 1,
2909  GetClassVersion(), GetName(), otherClass.Data(), otherBase->GetBaseVersion(),
2910  GetClassVersion(), localBase->GetBaseVersion(), localClass.Data());
2911  otherBase->SetErrorMessage(msg);
2912 
2913  } else if (!otherBaseClass->IsVersioned() && localBase->GetBaseCheckSum() != otherBase->GetBaseCheckSum())
2914  {
2915  TVirtualStreamerInfo *localBaseInfo = otherBaseClass->FindStreamerInfo(localBase->GetBaseCheckSum());
2916  TVirtualStreamerInfo *otherBaseInfo = otherBaseClass->FindStreamerInfo(otherBase->GetBaseCheckSum());
2917  if (localBaseInfo == otherBaseInfo ||
2918  localBaseInfo->CompareContent(0,otherBaseInfo,kFALSE,kFALSE,file) ) {
2919  // They are equivalent, no problem.
2920  continue;
2921  }
2922  TString msg;
2923  msg.Form(" The StreamerInfo of class %s read from %s%s\n"
2924  " has the same version (=%d) as the active class but a different checksum.\n"
2925  " You should update the version to ClassDef(%s,%d).\n"
2926  " The objects on this file might not be readable because:\n"
2927  " 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).",
2928  GetName(), file ? "file " : "", file ? file->GetName() : "", fClassVersion, GetName(), fClassVersion + 1,
2929  GetClassVersion(), GetName(), otherClass.Data(), otherBase->GetBaseCheckSum(),
2930  GetClassVersion(), localBase->GetBaseCheckSum(), localClass.Data());
2931  otherBase->SetErrorMessage(msg);
2932  }
2933  }
2934  }
2935  if (!result && !complete) {
2936  return result;
2937  }
2938  // Next the datamembers
2939  done = kFALSE;
2940  next.Reset();
2941  infonext.Reset();
2942 
2943  TMemberInfo local(GetClass());
2944  TMemberInfo other(cl ? cl : info->GetClass());
2945  UInt_t idx = 0;
2946  while(!done) {
2947  local.Clear();
2948  other.Clear();
2949  el = (TStreamerElement*)next();
2950  while (el && (el->IsBase() || el->IsA() == TStreamerArtificial::Class())) {
2951  el = (TStreamerElement*)next();
2952  ++idx;
2953  }
2954  if (el) {
2955  local.SetName( el->GetName() );
2956  local.SetClassName( el->GetTypeName() );
2957  local.SetComment( el->GetTitle() );
2958  local.SetDataType( el->GetType() );
2959  }
2960  if (cl) {
2961  TDataMember *tdm = (TDataMember*)membernext();
2962  while(tdm && ( (!tdm->IsPersistent()) || (tdm->Property()&kIsStatic) || (el && local.fName != tdm->GetName()) )) {
2963  tdm = (TDataMember*)membernext();
2964  }
2965  if (tdm) {
2966  other.SetName( tdm->GetName() );
2967  other.SetClassName( tdm->GetTrueTypeName() );
2968  other.SetComment( tdm->GetTitle() );
2969  if (tdm->GetDataType()) {
2970  // Need to update the type for arrays.
2971  if (tdm->IsaPointer()) {
2972  if (tdm->GetDataType()->GetType() == TVirtualStreamerInfo::kChar && !tdm->GetArrayDim() && tdm->GetArrayIndex()[0]==0) {
2973  other.SetDataType( TVirtualStreamerInfo::kCharStar );
2974  } else {
2975  other.SetDataType( tdm->GetDataType()->GetType() + TVirtualStreamerInfo::kOffsetP);
2976  }
2977  } else {
2978  if (tdm->GetArrayDim()) {
2979  other.SetDataType( tdm->GetDataType()->GetType() + TVirtualStreamerInfo::kOffsetL);
2980  } else {
2981  other.SetDataType( tdm->GetDataType()->GetType() );
2982  }
2983  }
2984  }
2985  } else if (el==0) {
2986  done = kTRUE;
2987  break;
2988  }
2989  } else {
2990  infoel = (TStreamerElement*)infonext();
2991  while (infoel && (infoel->IsBase() || infoel->IsA() == TStreamerArtificial::Class())) {
2992  infoel = (TStreamerElement*)infonext();
2993  }
2994  if (infoel) {
2995  other.SetName( infoel->GetName() );
2996  other.SetClassName( infoel->GetTypeName() );
2997  other.SetComment( infoel->GetTitle() );
2998  other.SetDataType( infoel->GetType() );
2999  } else if (el==0) {
3000  done = kTRUE;
3001  break;
3002  }
3003  }
3004  if (local!=other) {
3005  if (warn) {
3006  if (!el) {
3007  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"
3008  " %s %s; //%s"
3010  ,other.fClassName.Data(),other.fName.Data(),other.fComment.Data());
3011 
3012  } else if (other.fName.Length()==0) {
3013  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"
3014  " %s %s; //%s"
3016  ,local.fClassName.Data(),local.fName.Data(),local.fComment.Data());
3017  } else {
3018  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"
3019  " %s %s; //%s\n"
3020  "vs\n"
3021  " %s %s; //%s"
3023  ,local.fClassName.Data(),local.fName.Data(),local.fComment.Data()
3024  ,other.fClassName.Data(),other.fName.Data(),other.fComment.Data());
3025  }
3026  }
3027  result = result && kFALSE;
3028  if (!complete) return result;
3029  }
3030  ++idx;
3031  }
3032  return result;
3033 }
3034 
3035 
3036 ////////////////////////////////////////////////////////////////////////////////
3037 /// Compute total size of all persistent elements of the class
3038 
3040 {
3042  //faster and more precise to use last element offset +size
3043  //on 64 bit machines, offset may be forced to be a multiple of 8 bytes
3044  fSize = element ? element->GetOffset() + element->GetSize() : 0;
3045  if (fNVirtualInfoLoc > 0 && (fVirtualInfoLoc[0]+sizeof(TStreamerInfo*)) >= (ULong_t)fSize) {
3046  fSize = fVirtualInfoLoc[0] + sizeof(TStreamerInfo*);
3047  }
3048 
3049  // On some platform and in some case of layout non-basic data types needs
3050  // to be aligned. So let's be on the safe side and align on the size of
3051  // the pointers. (Question: is that the right thing on x32 ABI ?)
3052  constexpr size_t kSizeOfPtr = sizeof(void*);
3053  if ((fSize % kSizeOfPtr) != 0) {
3054  fSize = fSize - (fSize % kSizeOfPtr) + kSizeOfPtr;
3055  }
3056 }
3057 
3058 ////////////////////////////////////////////////////////////////////////////////
3059 /// Recursively mark streamer infos for writing to a file.
3060 ///
3061 /// Will force this TStreamerInfo to the file and also
3062 /// all the dependencies.
3063 /// If argument force > 0 the loop on class dependencies is forced.
3064 /// This function is called when streaming a class that contains
3065 /// a null pointer. In this case, the TStreamerInfo for the class
3066 /// with the null pointer must be written to the file and also all
3067 /// the TStreamerInfo of all the classes referenced by the class.
3068 /// We must be given a file to write to.
3069 
3071 {
3072  if (!file) {
3073  return;
3074  }
3075  // Get the given file's list of streamer infos marked for writing.
3076  TArrayC* cindex = file->GetClassIndex();
3077  //the test below testing fArray[fNumber]>1 is to avoid a recursivity
3078  //problem in some cases like:
3079  // class aProblemChild: public TNamed {
3080  // aProblemChild *canBeNull;
3081  // };
3082  if ( // -- Done if already marked, and we are not forcing, or forcing is blocked.
3083  (cindex->fArray[fNumber] && !force) || // Streamer info is already marked, and not forcing, or
3084  (cindex->fArray[fNumber] > 1) // == 2 means ignore forcing to prevent infinite recursion.
3085  ) {
3086  return;
3087  }
3088  // We do not want to write streamer info to the file
3089  // for std::string.
3090  static TClassRef string_classref("string");
3091  if (fClass == string_classref) { // We are std::string.
3092  return;
3093  }
3094  // We do not want to write streamer info to the file
3095  // for STL containers.
3096  if (fClass==0) {
3097  // Build or BuildCheck has not been called yet.
3098  // Let's use another means of checking.
3099  if (fElements && fElements->GetEntries()==1 && strcmp("This",fElements->UncheckedAt(0)->GetName())==0) {
3100  // We are an STL collection.
3101  return;
3102  }
3103  } else if (fClass->GetCollectionProxy()) { // We are an STL collection.
3104  return;
3105  }
3106  // Mark ourselves for output, and block
3107  // forcing to prevent infinite recursion.
3108  cindex->fArray[fNumber] = 2;
3109  // Signal the file that the marked streamer info list has changed.
3110  cindex->fArray[0] = 1;
3111  // Recursively mark the streamer infos for
3112  // all of our elements.
3113  TIter next(fElements);
3114  TStreamerElement* element = (TStreamerElement*) next();
3115  for (; element; element = (TStreamerElement*) next()) {
3116  if (element->IsTransient()) continue;
3117  TClass* cl = element->GetClassPointer();
3118  if (cl) {
3119  TVirtualStreamerInfo* si = 0;
3120  if (cl->Property() & kIsAbstract) {
3121  // If the class of the element is abstract, register the
3122  // TStreamerInfo only if it has already been built.
3123  // Otherwise call cl->GetStreamerInfo() would generate an
3124  // incorrect StreamerInfo.
3125  si = cl->GetCurrentStreamerInfo();
3126  } else {
3127  si = cl->GetStreamerInfo();
3128  }
3129  if (si) {
3130  si->ForceWriteInfo(file, force);
3131  }
3132  }
3133  }
3134 }
3135 
3136 ////////////////////////////////////////////////////////////////////////////////
3137 /// Assuming that obj points to (the part of) an object that is of the
3138 /// type described by this streamerInfo, return the actual type of the
3139 /// object (i.e. the type described by this streamerInfo is a base class
3140 /// of the actual type of the object.
3141 /// This routine should only be called if the class described by this
3142 /// StreamerInfo is 'emulated'.
3143 
3144 TClass *TStreamerInfo::GetActualClass(const void *obj) const
3145 {
3146  R__ASSERT(!fClass->IsLoaded());
3147 
3148  if (fNVirtualInfoLoc != 0) {
3149  TStreamerInfo *allocator = *(TStreamerInfo**)( (const char*)obj + fVirtualInfoLoc[0] );
3150  if (allocator) return allocator->GetClass();
3151  }
3152  return (TClass*)fClass;
3153 }
3154 
3155 ////////////////////////////////////////////////////////////////////////////////
3156 /// Return true if the checksum passed as argument is one of the checksum
3157 /// value produced by the older checksum calculation algorithm.
3158 
3160 {
3161  for(UInt_t i = 1; i < TClass::kLatestCheckSum; ++i) {
3162  if ( checksum == GetCheckSum( (TClass::ECheckSum) i) ) return kTRUE;
3163  }
3164  return kFALSE;
3165 }
3166 
3167 ////////////////////////////////////////////////////////////////////////////////
3168 /// Recalculate the checksum of this TStreamerInfo based on its code.
3169 ///
3170 /// The class ckecksum is used by the automatic schema evolution algorithm
3171 /// to uniquely identify a class version.
3172 /// The check sum is built from the names/types of base classes and
3173 /// data members.
3174 /// The valid range of code is determined by ECheckSum.
3175 /// - kNoEnum: data members of type enum are not counted in the checksum
3176 /// - kNoRange: return the checksum of data members and base classes, not including the ranges and array size found in comments.
3177 /// - kWithTypeDef: use the sugared type name in the calculation.
3178 ///
3179 /// This is needed for backward compatibility.
3180 /// ### WARNING
3181 /// This function must be kept in sync with TClass::GetCheckSum.
3182 /// They are both used to handle backward compatibility and should both return the same values.
3183 /// TStreamerInfo uses the information in TStreamerElement while TClass uses the information
3184 /// from TClass::GetListOfBases and TClass::GetListOfDataMembers.
3185 /// Original algorithm from Victor Perevovchikov (perev@bnl.gov).
3186 
3188 {
3189  // kCurrentCheckSum (0) should be kept for backward compatibility, to be
3190  // able to use the inequality checks, we need to set the code to the largest
3191  // value.
3193 
3194  UInt_t id = 0;
3195 
3196  int il;
3197  TString name = GetName();
3198  TString type;
3199  il = name.Length();
3200  for (int i=0; i<il; i++) id = id*3+name[i];
3201 
3202  TIter next(GetElements());
3203  TStreamerElement *el;
3204  while ( (el=(TStreamerElement*)next()) && !fClass->GetCollectionProxy()) { // loop over bases if not a proxied collection
3205  if (el->IsBase()) {
3206  name = el->GetName();
3207  il = name.Length();
3208  for (int i=0; i<il; i++) id = id*3+name[i];
3209  if (code > TClass::kNoBaseCheckSum && el->IsA() == TStreamerBase::Class()) {
3210  TStreamerBase *base = (TStreamerBase*)el;
3211  id = id*3 + base->GetBaseCheckSum();
3212  }
3213  }
3214  } /* End of Base Loop */
3215 
3216  next.Reset();
3217  while ( (el=(TStreamerElement*)next()) ) {
3218  if (el->IsBase()) continue;
3219 
3220  // humm can we tell if a TStreamerElement is an enum?
3221  // Maybe something like:
3222  Bool_t isenum = kFALSE;
3223  if ( el->GetType()==3 && gROOT->GetType(el->GetTypeName())==0) {
3224  // If the type is not an enum but a typedef to int then
3225  // el->GetTypeName() should be return 'int'
3226  isenum = kTRUE;
3227  }
3228  if ( (code > TClass::kNoEnum) && isenum) id = id*3 + 1;
3229 
3230  name = el->GetName(); il = name.Length();
3231 
3232  int i;
3233  for (i=0; i<il; i++) id = id*3+name[i];
3234 
3235  if (code == TClass::kReflex || code == TClass::kReflexNoComment) {
3236  // With TClass::kReflexV5 we do not want the Long64 in the name
3237  // nor any typedef.
3239 
3240  } else if (code <= TClass::kWithTypeDef) {
3241  // humm ... In the streamerInfo we only have the desugared/normalized
3242  // names, so we are unable to calculate the name with typedefs ...
3243  // except for the case of the ROOT typedef (Int_t, etc.) which are
3244  // kept by TClassEdit::ResolveTypedef(typeName) but not by TCling's
3245  // normalization ...
3246  //
3247  type = el->GetTypeName();
3248  } else {
3250  }
3251  if (TClassEdit::IsSTLCont(type)) {
3253  }
3254  if (code == TClass::kReflex || code == TClass::kReflexNoComment) {
3255  type.ReplaceAll("ULong64_t","unsigned long long");
3256  type.ReplaceAll("Long64_t","long long");
3257  type.ReplaceAll("signed char","char");
3258  type.ReplaceAll("<signed char","<char");
3259  type.ReplaceAll(",signed char",",char");
3260  if (type=="signed char") type = "char";
3261  }
3262 
3263  il = type.Length();
3264  for (i=0; i<il; i++) id = id*3+type[i];
3265 
3266  int dim = el->GetArrayDim();
3267  if (dim) {
3268  for (i=0;i<dim;i++) id = id*3+el->GetMaxIndex(i);
3269  }
3270 
3271 
3272  if (code > TClass::kNoRange) {
3273  const char *left;
3274  if (code > TClass::kNoRangeCheck)
3276  else
3277  left = strstr(el->GetTitle(),"[");
3278  if (left) {
3279  const char *right = strstr(left,"]");
3280  if (right) {
3281  ++left;
3282  while (left != right) {
3283  id = id*3 + *left;
3284  ++left;
3285  }
3286  }
3287  }
3288  }
3289  }
3290  return id;
3291 }
3292 
3293 ////////////////////////////////////////////////////////////////////////////////
3294 
3295 static void R__WriteConstructorBody(FILE *file, TIter &next)
3296 {
3297  TStreamerElement *element = 0;
3298  next.Reset();
3299  while ((element = (TStreamerElement*)next())) {
3304  if(element->GetArrayLength() <= 1) {
3305  fprintf(file," %s = 0;\n",element->GetName());
3306  } else {
3307  fprintf(file," memset(%s,0,%d);\n",element->GetName(),element->GetSize());
3308  }
3309  }
3310  if (TVirtualStreamerInfo::kOffsetP <= element->GetType() && element->GetType() < TVirtualStreamerInfo::kObject ) {
3311  fprintf(file," %s = 0;\n",element->GetName());
3312  }
3313  }
3314 }
3315 
3316 ////////////////////////////////////////////////////////////////////////////////
3317 /// Write down the body of the 'move' constructor.
3318 
3319 static void R__WriteMoveConstructorBody(FILE *file, const TString &protoname, TIter &next)
3320 {
3321  TStreamerElement *element = 0;
3322  next.Reset();
3323  Bool_t atstart = kTRUE;
3324  while ((element = (TStreamerElement*)next())) {
3325  if (element->IsBase()) {
3326  if (atstart) { fprintf(file," : "); atstart = kFALSE; }
3327  else fprintf(file," , ");
3328  fprintf(file, "%s(const_cast<%s &>( rhs ))\n", element->GetName(),protoname.Data());
3329  } else {
3330  if (element->GetArrayLength() <= 1) {
3331  if (atstart) { fprintf(file," : "); atstart = kFALSE; }
3332  else fprintf(file," , ");
3333  fprintf(file, "%s(const_cast<%s &>( rhs ).%s)\n",element->GetName(),protoname.Data(),element->GetName());
3334  }
3335  }
3336  }
3337  fprintf(file,"{\n");
3338  fprintf(file," // This is NOT a copy constructor. This is actually a move constructor (for stl container's sake).\n");
3339  fprintf(file," // Use at your own risk!\n");
3340  fprintf(file," (void)rhs; // avoid warning about unused parameter\n");
3341  next.Reset();
3342  Bool_t defMod = kFALSE;
3343  while ((element = (TStreamerElement*)next())) {
3346  || element->GetType() == TVirtualStreamerInfo::kAnyPnoVT)
3347  {
3348  if (!defMod) { fprintf(file," %s &modrhs = const_cast<%s &>( rhs );\n",protoname.Data(),protoname.Data()); defMod = kTRUE; };
3349  const char *ename = element->GetName();
3350  const char *colon2 = strstr(ename,"::");
3351  if (colon2) ename = colon2+2;
3352  if(element->GetArrayLength() <= 1) {
3353  fprintf(file," modrhs.%s = 0;\n",ename);
3354  } else {
3355  fprintf(file," memset(modrhs.%s,0,%d);\n",ename,element->GetSize());
3356  }
3357  } else {
3358  const char *ename = element->GetName();
3359  if (element->GetType() == kCharStar) {
3360  if (!defMod) {
3361  fprintf(file," %s &modrhs = const_cast<%s &>( rhs );\n",protoname.Data(),protoname.Data()); defMod = kTRUE;
3362  };
3363  fprintf(file," modrhs.%s = 0;\n",ename);
3364  } else if (TVirtualStreamerInfo::kOffsetP <= element->GetType() && element->GetType() < TVirtualStreamerInfo::kObject ) {
3365  if (!defMod) {
3366  fprintf(file," %s &modrhs = const_cast<%s &>( rhs );\n",protoname.Data(),protoname.Data()); defMod = kTRUE;
3367  };
3368  fprintf(file," modrhs.%s = 0;\n",ename);
3369  } else if (element->GetArrayLength() > 1) {
3370  // FIXME: Need to add support for variable length array.
3371  if (element->GetArrayDim() == 1) {
3372  fprintf(file," for (Int_t i=0;i<%d;i++) %s[i] = rhs.%s[i];\n",element->GetArrayLength(),ename,ename);
3373  } else if (element->GetArrayDim() >= 2) {
3374  fprintf(file," for (Int_t i=0;i<%d;i++) (&(%s",element->GetArrayLength(),ename);
3375  for (Int_t d = 0; d < element->GetArrayDim(); ++d) {
3376  fprintf(file,"[0]");
3377  }
3378  fprintf(file,"))[i] = (&(rhs.%s",ename);
3379  for (Int_t d = 0; d < element->GetArrayDim(); ++d) {
3380  fprintf(file,"[0]");
3381  }
3382  fprintf(file,"))[i];\n");
3383  }
3384  } else if (element->GetType() == TVirtualStreamerInfo::kSTLp) {
3385  if (!defMod) { fprintf(file," %s &modrhs = const_cast<%s &>( rhs );\n",protoname.Data(),protoname.Data()); defMod = kTRUE; };
3386  fprintf(file," modrhs.%s = 0;\n",ename);
3387  } else if (element->GetType() == TVirtualStreamerInfo::kSTL) {
3388  if (!defMod) {
3389  fprintf(file," %s &modrhs = const_cast<%s &>( rhs );\n",protoname.Data(),protoname.Data()); defMod = kTRUE;
3390  }
3391  TClass *cle = element->GetClassPointer();
3392  TVirtualCollectionProxy *proxy = cle ? element->GetClassPointer()->GetCollectionProxy() : 0;
3393  std::string method_name = "clear";
3394  if (!element->TestBit(TStreamerElement::kDoNotDelete) && proxy && (((TStreamerSTL*)element)->GetSTLtype() == ROOT::kSTLbitset)) {
3395  method_name = "reset";
3396  }
3397  if (element->IsBase()) {
3398  fprintf(file," modrhs.%s();\n", method_name.c_str());
3399  } else {
3400  fprintf(file," modrhs.%s.%s();\n",ename, method_name.c_str());
3401  }
3402  }
3403  }
3404  }
3405 }
3406 
3407 ////////////////////////////////////////////////////////////////////////////////
3408 
3409 static void R__WriteDestructorBody(FILE *file, TIter &next)
3410 {
3411  TStreamerElement *element = 0;
3412  next.Reset();
3413  while ((element = (TStreamerElement*)next())) {
3416  || element->GetType() == TVirtualStreamerInfo::kAnyPnoVT)
3417  {
3418  const char *ename = element->GetName();
3419  const char *colon2 = strstr(ename,"::");
3420  if (colon2) ename = colon2+2;
3421  if (element->TestBit(TStreamerElement::kDoNotDelete)) {
3422  if(element->GetArrayLength() <= 1) {
3423  fprintf(file," %s = 0;\n",ename);
3424  } else {
3425  fprintf(file," memset(%s,0,%d);\n",ename,element->GetSize());
3426  }
3427  } else {
3428  if(element->GetArrayLength() <= 1) {
3429  fprintf(file," delete %s; %s = 0;\n",ename,ename);
3430  } else {
3431  fprintf(file," for (Int_t i=0;i<%d;i++) delete %s[i]; memset(%s,0,%d);\n",element->GetArrayLength(),ename,ename,element->GetSize());
3432  }
3433  }
3434  }
3435  if (element->GetType() == TVirtualStreamerInfo::kCharStar) {
3436  const char *ename = element->GetName();
3437  if (element->TestBit(TStreamerElement::kDoNotDelete)) {
3438  fprintf(file," %s = 0;\n",ename);
3439  } else {
3440  fprintf(file," delete [] %s; %s = 0;\n",ename,ename);
3441  }
3442  }
3443  if (TVirtualStreamerInfo::kOffsetP <= element->GetType() && element->GetType() < TVirtualStreamerInfo::kObject ) {
3444  const char *ename = element->GetName();
3445  if (element->TestBit(TStreamerElement::kDoNotDelete)) {
3446  fprintf(file," %s = 0;\n",ename);
3447  } else if (element->HasCounter()) {
3448  fprintf(file," delete %s; %s = 0;\n",ename,ename);
3449  } else {
3450  fprintf(file," delete [] %s; %s = 0;\n",ename,ename);
3451  }
3452  }
3453  if (element->GetType() == TVirtualStreamerInfo::kSTL || element->GetType() == TVirtualStreamerInfo::kSTLp) {
3454  const char *ename = element->GetName();
3455  const char *prefix = "";
3456  if ( element->GetType() == TVirtualStreamerInfo::kSTLp ) {
3457  prefix = "*";
3458  } else if ( element->IsBase() ) {
3459  ename = "this";
3460  }
3461  TClass *cle = element->GetClassPointer();
3462  TVirtualCollectionProxy *proxy = cle ? element->GetClassPointer()->GetCollectionProxy() : 0;
3463  if (!element->TestBit(TStreamerElement::kDoNotDelete) && proxy) {
3464  Int_t stltype = ((TStreamerSTL*)element)->GetSTLtype();
3465 
3466  if (proxy->HasPointers()) {
3467  fprintf(file," std::for_each( (%s %s).rbegin(), (%s %s).rend(), DeleteObjectFunctor() );\n",prefix,ename,prefix,ename);
3468  //fprintf(file," %s::iterator iter;\n");
3469  //fprintf(file," %s::iterator begin = (%s %s).begin();\n");
3470  //fprintf(file," %s::iterator end (%s %s).end();\n");
3471  //fprintf(file," for( iter = begin; iter != end; ++iter) { delete *iter; }\n");
3472  } else {
3473  if (stltype == ROOT::kSTLmap || stltype == ROOT::kSTLmultimap) {
3475  std::vector<std::string> inside;
3476  int nestedLoc;
3477  TClassEdit::GetSplit(enamebasic, inside, nestedLoc, TClassEdit::kLong64);
3478  if (inside[1][inside[1].size()-1]=='*' || inside[2][inside[2].size()-1]=='*') {
3479  fprintf(file," std::for_each( (%s %s).rbegin(), (%s %s).rend(), DeleteObjectFunctor() );\n",prefix,ename,prefix,ename);
3480  }
3481  }
3482  }
3483  }
3484  if ( prefix[0] ) {
3485  fprintf(file," delete %s; %s = 0;\n",ename,ename);
3486  }
3487  }
3488  }
3489 }
3490 
3491 ////////////////////////////////////////////////////////////////////////////////
3492 /// Write the Declaration of class.
3493 
3494 void TStreamerInfo::GenerateDeclaration(FILE *fp, FILE *sfp, const TList *subClasses, Bool_t top)
3495 {
3496  if (fClassVersion == -3) {
3497  return;
3498  }
3499 
3500  Bool_t needGenericTemplate = fElements==0 || fElements->GetEntries() == 0;
3501  Bool_t isTemplate = kFALSE;
3502  const char *clname = GetName();
3503  TString template_protoname;
3504  if (strchr(clname, ':')) {
3505  // We might have a namespace in front of the classname.
3506  Int_t len = strlen(clname);
3507  const char *name = clname;
3508  UInt_t nest = 0;
3509  UInt_t pr_pos = 0;
3510  for (Int_t cur = 0; cur < len; ++cur) {
3511  switch (clname[cur]) {
3512  case '<':
3513  ++nest;
3514  pr_pos = cur;
3515  isTemplate = kTRUE;
3516  break;
3517  case '>':
3518  if (nest == 0) { cur = len; continue; } // the name is not well formed, give up.
3519  --nest;
3520  break;
3521  case ':': {
3522  if (nest == 0 && clname[cur+1] == ':') {
3523  // We have a scope
3524  isTemplate = kFALSE;
3525  name = clname + cur + 2;
3526  }
3527  break;
3528  }
3529  }
3530  }
3531  if (isTemplate) {
3532  template_protoname.Append(clname,pr_pos);
3533  }
3534  clname = name;
3535  } else {
3536  const char *where = strstr(clname, "<");
3537  isTemplate = where != 0;
3538  if (isTemplate) {
3539  template_protoname.Append(clname,where-clname);
3540  }
3541  }
3542 
3543  if (needGenericTemplate && isTemplate) {
3544  TString templateName(TMakeProject::GetHeaderName("template "+template_protoname,0));
3545  fprintf(fp, "#ifndef %s_h\n", templateName.Data());
3546  fprintf(fp, "#define %s_h\n", templateName.Data());
3547  }
3548 
3549  TString protoname;
3550  UInt_t numberOfNamespaces = TMakeProject::GenerateClassPrefix(fp, GetName(), top, protoname, 0, kFALSE, needGenericTemplate);
3551 
3552  // Generate class statement with base classes.
3553  TStreamerElement *element;
3554  TIter next(fElements);
3555  Int_t nbase = 0;
3556  while ((element = (TStreamerElement*)next())) {
3557  if (!element->IsBase()) continue;
3558  nbase++;
3559  const char *ename = element->GetName();
3560  if (nbase == 1) fprintf(fp," : public %s",ename);
3561  else fprintf(fp," , public %s",ename);
3562  }
3563  fprintf(fp," {\n");
3564 
3565  // Generate forward declaration nested classes.
3566  if (subClasses && subClasses->GetEntries()) {
3567  Bool_t needheader = true;
3568 
3569  TIter subnext(subClasses);
3570  TStreamerInfo *subinfo;
3571  Int_t len = strlen(GetName());
3572  while ((subinfo = (TStreamerInfo*)subnext())) {
3573  if (strncmp(GetName(),subinfo->GetName(),len)==0 && (subinfo->GetName()[len]==':') ) {
3574  if (subinfo->GetName()[len+1]==':' && strstr(subinfo->GetName()+len+2,":")==0) {
3575  if (needheader) {
3576  fprintf(fp,"\npublic:\n");
3577  fprintf(fp,"// Nested classes forward declaration.\n");
3578  needheader = false;
3579  }
3580  TString sub_protoname;
3581  UInt_t sub_numberOfClasses = 0;
3582  UInt_t sub_numberOfNamespaces;
3583  if (subinfo->GetClassVersion() == -3) {
3584  sub_numberOfNamespaces = TMakeProject::GenerateClassPrefix(fp, subinfo->GetName() + len+2, kFALSE, sub_protoname, &sub_numberOfClasses, 3);
3585  } else {
3586  sub_numberOfNamespaces = TMakeProject::GenerateClassPrefix(fp, subinfo->GetName() + len+2, kFALSE, sub_protoname, &sub_numberOfClasses, kFALSE);
3587  fprintf(fp, ";\n");
3588  }
3589 
3590  for (UInt_t i = 0;i < sub_numberOfClasses;++i) {
3591  fprintf(fp, "}; // end of class.\n");
3592  }
3593  if (sub_numberOfNamespaces > 0) {
3594  Error("GenerateDeclaration","Nested classes %s thought to be inside a namespace inside the class %s",subinfo->GetName(),GetName());
3595  }
3596  }
3597  }
3598  }
3599  }
3600 
3601  fprintf(fp,"\npublic:\n");
3602  fprintf(fp,"// Nested classes declaration.\n");
3603 
3604  // Generate nested classes.
3605  if (subClasses && subClasses->GetEntries()) {
3606  TIter subnext(subClasses,kIterBackward);
3607  TStreamerInfo *subinfo;
3608  Int_t len = strlen(GetName());
3609  while ((subinfo = (TStreamerInfo*)subnext())) {
3610  if (strncmp(GetName(),subinfo->GetName(),len)==0 && (subinfo->GetName()[len]==':')) {
3611  if (subinfo->GetName()[len+1]==':' && strstr(subinfo->GetName()+len+2,":")==0) {
3612  subinfo->GenerateDeclaration(fp, sfp, subClasses, kFALSE);
3613  }
3614  }
3615  }
3616  }
3617 
3618  fprintf(fp,"\npublic:\n");
3619  fprintf(fp,"// Data Members.\n");
3620 
3621  {
3622  // Generate data members.
3623  TString name(128);
3624  Int_t ltype = 12;
3625  Int_t ldata = 10;
3626  Int_t lt,ld,is;
3627  TString line;
3628  line.Resize(kMaxLen);
3629  next.Reset();
3630  while ((element = (TStreamerElement*)next())) {
3631 
3632  if (element->IsBase()) continue;
3633  const char *ename = element->GetName();
3634 
3635  name = ename;
3636  for (Int_t i=0;i < element->GetArrayDim();i++) {
3637  name += TString::Format("[%d]",element->GetMaxIndex(i));
3638  }
3639  name += ";";
3640  ld = name.Length();
3641 
3642  TString enamebasic = element->GetTypeNameBasic();
3643  if (element->IsA() == TStreamerSTL::Class()) {
3644  // If we have a map, multimap, set or multiset,
3645  // and the key is a class, we need to replace the
3646  // container by a vector since we don't have the
3647  // comparator function.
3648  Int_t stltype = ((TStreamerSTL*)element)->GetSTLtype();
3649  switch (stltype) {
3650  case ROOT::kSTLmap:
3651  case ROOT::kSTLmultimap:
3652  case ROOT::kSTLset:
3653  case ROOT::kSTLmultiset:
3656  {
3657  enamebasic = TMakeProject::UpdateAssociativeToVector(enamebasic);
3658  }
3659  default:
3660  // nothing to do.
3661  break;
3662  }
3663  }
3664 
3665  lt = enamebasic.Length();
3666 
3667  line = " ";
3668  line += enamebasic;
3669  if (lt>=ltype) ltype = lt+1;
3670 
3671  for (is = 3+lt; is < (3+ltype); ++is) line += ' ';
3672 
3673  line += name;
3674  if (element->IsaPointer() && !strchr(line,'*')) line[2+ltype] = '*';
3675 
3676  if (ld>=ldata) ldata = ld+1;
3677  for (is = 3+ltype+ld; is < (3+ltype+ldata); ++is) line += ' ';
3678 
3679  line += " //";
3680  line += element->GetTitle();
3681  fprintf(fp,"%s\n",line.Data());
3682  }
3683  }
3684  if (needGenericTemplate && isTemplate) {
3685  // Generate default functions, ClassDef and trailer.
3686  fprintf(fp,"\n %s() {\n",protoname.Data());
3687  R__WriteConstructorBody(fp,next);
3688  fprintf(fp," }\n");
3689  fprintf(fp," %s(const %s & rhs )\n",protoname.Data(),protoname.Data());
3690  R__WriteMoveConstructorBody(fp,protoname,next);
3691  fprintf(fp," }\n");
3692  fprintf(fp," virtual ~%s() {\n",protoname.Data());
3693  R__WriteDestructorBody(fp,next);
3694  fprintf(fp," }\n\n");
3695 
3696  } else {
3697  // Generate default functions, ClassDef and trailer.
3698  fprintf(fp,"\n %s();\n",protoname.Data());
3699  fprintf(fp," %s(const %s & );\n",protoname.Data(),protoname.Data());
3700  fprintf(fp," virtual ~%s();\n\n",protoname.Data());
3701 
3702  // Add the implementations to the source.cxx file.
3704  fprintf(sfp,"#ifndef %s_cxx\n",guard.Data());
3705  fprintf(sfp,"#define %s_cxx\n",guard.Data());
3706  fprintf(sfp,"%s::%s() {\n",GetName(),protoname.Data());
3707  R__WriteConstructorBody(sfp,next);
3708  fprintf(sfp,"}\n");
3709 
3710  fprintf(sfp,"%s::%s(const %s & rhs)\n",GetName(),protoname.Data(),protoname.Data());
3711  R__WriteMoveConstructorBody(sfp,protoname,next);
3712  fprintf(sfp,"}\n");
3713 
3714  fprintf(sfp,"%s::~%s() {\n",GetName(),protoname.Data());
3715  R__WriteDestructorBody(sfp,next);
3716  fprintf(sfp,"}\n");
3717  fprintf(sfp,"#endif // %s_cxx\n\n",guard.Data());
3718  }
3719 
3720  TClass *cl = gROOT->GetClass(GetName());
3721  if (fClassVersion > 1 || (cl && cl->IsTObject()) ) {
3722  // add 1 to class version in case we didn't manage reproduce the class layout to 100%.
3723  if (fClassVersion == 0) {
3724  // If the class was declared 'transient', keep it that way.
3725  fprintf(fp," ClassDef(%s,%d); // Generated by MakeProject.\n",protoname.Data(),0);
3726  } else {
3727  fprintf(fp," ClassDef(%s,%d); // Generated by MakeProject.\n",protoname.Data(),fClassVersion + 1);
3728  }
3729  }
3730  fprintf(fp,"};\n");
3731 
3732  for(UInt_t i=0;i<numberOfNamespaces;++i) {
3733  fprintf(fp,"} // namespace\n");
3734  }
3735 
3736  if (needGenericTemplate && isTemplate) {
3737  fprintf(fp,"#endif // generic template declaration\n");
3738  }
3739 }
3740 
3741 ////////////////////////////////////////////////////////////////////////////////
3742 /// Add to the header file, the \#include need for this class.
3743 
3744 UInt_t TStreamerInfo::GenerateIncludes(FILE *fp, char *inclist, const TList *extrainfos)
3745 {
3746  if (inclist[0]==0) {
3747  // Always have this include for ClassDef.
3748  TMakeProject::AddInclude( fp, "Rtypes.h", kFALSE, inclist);
3749  }
3750  UInt_t ninc = 0;
3751 
3752  const char *clname = GetName();
3753  if (strchr(clname,'<')) {
3754  // This is a template, we need to check the template parameter.
3755  ninc += TMakeProject::GenerateIncludeForTemplate(fp, clname, inclist, kFALSE, extrainfos);
3756  }
3757 
3758  TString name(1024);
3759  Int_t ltype = 10;
3760  Int_t ldata = 10;
3761  Int_t lt;
3762  Int_t ld;
3763  TIter next(fElements);
3764  TStreamerElement *element;
3765  Bool_t incRiostream = kFALSE;
3766  while ((element = (TStreamerElement*)next())) {
3767  //if (element->IsA() == TStreamerBase::Class()) continue;
3768  const char *ename = element->GetName();
3769  const char *colon2 = strstr(ename,"::");
3770  if (colon2) ename = colon2+2;
3771  name = ename;
3772  for (Int_t i=0;i < element->GetArrayDim();i++) {
3773  name += TString::Format("[%d]",element->GetMaxIndex(i));
3774  }
3775  ld = name.Length();
3776  lt = strlen(element->GetTypeName());
3777  if (ltype < lt) ltype = lt;
3778  if (ldata < ld) ldata = ld;
3779 
3780  //must include Riostream.h in case of an STL container
3781  if (!incRiostream && element->InheritsFrom(TStreamerSTL::Class())) {
3782  incRiostream = kTRUE;
3783  TMakeProject::AddInclude( fp, "Riostream.h", kFALSE, inclist);
3784  }
3785 
3786  //get include file name if any
3787  const char *include = element->GetInclude();
3788  if (!include[0]) continue;
3789 
3790  Bool_t greater = (include[0]=='<');
3791  include++;
3792 
3793  if (strncmp(include,"include/",8)==0) {
3794  include += 8;
3795  }
3796  if (strncmp(include,"include\\",9)==0) {
3797  include += 9;
3798  }
3799  if (strncmp(element->GetTypeName(),"pair<",strlen("pair<"))==0) {
3800  TMakeProject::AddInclude( fp, "utility", kTRUE, inclist);
3801  } else if (strncmp(element->GetTypeName(),"auto_ptr<",strlen("auto_ptr<"))==0) {
3802  TMakeProject::AddInclude( fp, "memory", kTRUE, inclist);
3803  } else {
3804  TString incName( include, strlen(include)-1 );
3805  incName = TMakeProject::GetHeaderName(incName,extrainfos);
3806  TMakeProject::AddInclude( fp, incName.Data(), greater, inclist);
3807  }
3808 
3809  if (strchr(element->GetTypeName(),'<')) {
3810  // This is a template, we need to check the template parameter.
3811  ninc += TMakeProject::GenerateIncludeForTemplate(fp, element->GetTypeName(), inclist, kFALSE, extrainfos);
3812  }
3813  }
3814  return ninc;
3815 }
3816 
3817 ////////////////////////////////////////////////////////////////////////////////
3818 /// Generate header file for the class described by this TStreamerInfo
3819 /// the function is called by TFile::MakeProject for each class in the file
3820 
3821 Int_t TStreamerInfo::GenerateHeaderFile(const char *dirname, const TList *subClasses, const TList *extrainfos)
3822 {
3823  // if (fClassVersion == -4) return 0;
3824  if ((fClass && fClass->GetCollectionType()) || TClassEdit::IsSTLCont(GetName())) return 0;
3825  if (strncmp(GetName(),"pair<",strlen("pair<"))==0) return 0;
3826  if (strncmp(GetName(),"auto_ptr<",strlen("auto_ptr<"))==0) return 0;
3827 
3828  TClass *cl = TClass::GetClass(GetName());
3829  if (cl) {
3830  if (cl->HasInterpreterInfo()) return 0; // skip known classes
3831  }
3832  Bool_t isTemplate = kFALSE;
3833  if (strchr(GetName(),':')) {
3834  UInt_t len = strlen(GetName());
3835  UInt_t nest = 0;
3836  UInt_t scope = 0;
3837  for(UInt_t i=len; i>0; --i) {
3838  switch(GetName()[i]) {
3839  case '>': ++nest; if (scope==0) { isTemplate = kTRUE; } break;
3840  case '<': --nest; break;
3841  case ':':
3842  if (nest==0 && GetName()[i-1]==':') {
3843  // We have a scope
3844  TString nsname(GetName(), i-1);
3845  cl = gROOT->GetClass(nsname);
3846  if (cl && (cl->Size()!=0 || (cl->Size()==0 && !cl->HasInterpreterInfo() /*empty 'base' class on file*/))) {
3847  // This class is actually nested.
3848  return 0;
3849  } else if (cl == 0 && extrainfos != 0) {
3850  TStreamerInfo *clinfo = (TStreamerInfo*)extrainfos->FindObject(nsname);
3851  if (clinfo && clinfo->GetClassVersion() == -5) {
3852  // This class is actually nested.
3853  return 0;
3854  }
3855  }
3856  ++scope;
3857  }
3858  break;
3859  }
3860  }
3861  }
3862  Bool_t needGenericTemplate = isTemplate && (fElements==0 || fElements->GetEntries()==0);
3863 
3864  if (gDebug) printf("generating code for class %s\n",GetName());
3865 
3866  // Open the file
3867 
3868  TString headername( TMakeProject::GetHeaderName( GetName(), extrainfos ) );
3869  TString filename;
3870  filename.Form("%s/%s.h",dirname,headername.Data());
3871 
3872  FILE *fp = fopen(filename.Data(),"w");
3873  if (!fp) {
3874  Error("MakeProject","Cannot open output file:%s\n",filename.Data());
3875  return 0;
3876  }
3877 
3878  filename.Form("%s/%sProjectHeaders.h",dirname,gSystem->BaseName(dirname));
3879  FILE *allfp = fopen(filename.Data(),"a");
3880  if (!allfp) {
3881  Error("MakeProject","Cannot open output file:%s\n",filename.Data());
3882  fclose(fp);
3883  return 0;
3884  }
3885  fprintf(allfp,"#include \"%s.h\"\n", headername.Data());
3886  fclose(allfp);
3887 
3888  char *inclist = new char[50000];
3889  inclist[0] = 0;
3890 
3891  // Generate class header.
3892  TDatime td;
3893  fprintf(fp,"//////////////////////////////////////////////////////////\n");
3894  fprintf(fp,"// This class has been generated by TFile::MakeProject\n");
3895  fprintf(fp,"// (%s by ROOT version %s)\n",td.AsString(),gROOT->GetVersion());
3896  fprintf(fp,"// from the StreamerInfo in file %s\n",gDirectory->GetFile()->GetName());
3897  fprintf(fp,"//////////////////////////////////////////////////////////\n");
3898  fprintf(fp,"\n");
3899  fprintf(fp,"\n");
3900  fprintf(fp,"#ifndef %s_h\n",headername.Data());
3901  fprintf(fp,"#define %s_h\n",headername.Data());
3902  TMakeProject::GenerateForwardDeclaration(fp, GetName(), inclist, kFALSE, needGenericTemplate, extrainfos);
3903  fprintf(fp,"\n");
3904 
3905  UInt_t ninc = 0;
3906  ninc += GenerateIncludes(fp, inclist, extrainfos);
3907  if (subClasses) {
3908  TIter subnext(subClasses);
3909  TStreamerInfo *subinfo;
3910  while ((subinfo = (TStreamerInfo*)subnext())) {
3911  ninc = subinfo->GenerateIncludes(fp, inclist, extrainfos);
3912  }
3913  }
3914  fprintf(fp,"\n");
3915 
3916  TString sourcename; sourcename.Form( "%s/%sProjectSource.cxx", dirname, gSystem->BaseName(dirname) );
3917  FILE *sfp = fopen( sourcename.Data(), "a" );
3918  if (sfp) {
3919  GenerateDeclaration(fp, sfp, subClasses);
3920  } else {
3921  Error("GenerateHeaderFile","Could not open %s for appending",sourcename.Data());
3922  }
3923  TMakeProject::GeneratePostDeclaration(fp, this, inclist);
3924 
3925  fprintf(fp,"#endif\n");
3926 
3927  delete [] inclist;
3928  fclose(fp);
3929  if (sfp) fclose(sfp);
3930  return 1;
3931 }
3932 
3933 ////////////////////////////////////////////////////////////////////////////////
3934 /// Compute data member offset.
3935 /// Return pointer to the Streamer function if one exists
3936 
3938 {
3939  TIter nextr(fClass->GetListOfRealData());
3940  char dmbracket[256];
3941  snprintf(dmbracket,255,"%s[",dm->GetName());
3942  Int_t offset = kMissing;
3943  if (!fClass->IsLoaded()) {
3944  // If the 'class' is not loaded, we do not have a TClass bootstrap and thus
3945  // the 'RealData' might not have enough information because of the lack
3946  // of proper ShowMember implementation.
3947  if (! (dm->Property() & kIsStatic) ) {
3948  // Give an offset only to non-static members.
3949  offset = dm->GetOffset();
3950  }
3951  }
3952  TRealData *rdm;
3953  while ((rdm = (TRealData*)nextr())) {
3954  char *rdmc = (char*)rdm->GetName();
3955  //next statement required in case a class and one of its parent class
3956  //have data members with the same name
3957  if (dm->IsaPointer() && rdmc[0] == '*') rdmc++;
3958 
3959  if (rdm->GetDataMember() != dm) continue;
3960  if (strcmp(rdmc,dm->GetName()) == 0) {
3961  offset = rdm->GetThisOffset();
3962  streamer = rdm->GetStreamer();
3963  break;
3964  }
3965  if (strcmp(rdm->GetName(),dm->GetName()) == 0) {
3966  if (rdm->IsObject()) {
3967  offset = rdm->GetThisOffset();
3968  streamer = rdm->GetStreamer();
3969  break;
3970  }
3971  }
3972  if (strstr(rdm->GetName(),dmbracket)) {
3973  offset = rdm->GetThisOffset();
3974  streamer = rdm->GetStreamer();
3975  break;
3976  }
3977  }
3978  return offset;
3979 }
3980 
3981 ////////////////////////////////////////////////////////////////////////////////
3982 /// Return the offset of the data member as indicated by this StreamerInfo.
3983 
3984 Int_t TStreamerInfo::GetOffset(const char *elementName) const
3985 {
3986  if (elementName == 0) return 0;
3987 
3988  Int_t offset = 0;
3989  TStreamerElement *elem = (TStreamerElement*)fElements->FindObject(elementName);
3990  if (elem) offset = elem->GetOffset();
3991 
3992  return offset;
3993 }
3994 
3995 ////////////////////////////////////////////////////////////////////////////////
3996 /// Return total size of all persistent elements of the class (with offsets).
3997 
3999 {
4000  return fSize;
4001 }
4002 
4003 ////////////////////////////////////////////////////////////////////////////////
4004 /// Return total size of all persistent elements of the class
4005 /// use GetSize if you want to get the real size in memory.
4006 
4008 {
4009  TIter next(fElements);
4010  TStreamerElement *element;
4011  Int_t asize = 0;
4012  while ((element = (TStreamerElement*)next())) {
4013  asize += element->GetSize();
4014  }
4015  return asize;
4016 }
4017 
4018 ////////////////////////////////////////////////////////////////////////////////
4019 /// Return the StreamerElement of "datamember" inside our
4020 /// class or any of its base classes.
4021 ///
4022 /// The offset information
4023 /// contained in the StreamerElement is related to its immediately
4024 /// containing class, so we return in 'offset' the offset inside
4025 /// our class.
4026 
4027 TStreamerElement* TStreamerInfo::GetStreamerElement(const char* datamember, Int_t& offset) const
4028 {
4029  if (!fElements) {
4030  return 0;
4031  }
4032 
4033  // Look first at the data members and base classes
4034  // of our class.
4035  TStreamerElement* element = (TStreamerElement*) fElements->FindObject(datamember);
4036  if (element) {
4037  offset = element->GetOffset();
4038  return element;
4039  }
4040 
4041  // Not found, so now try the data members and base classes
4042  // of the base classes of our class.
4043  if (fClass->HasDataMemberInfo()) {
4044  // Our class has a dictionary loaded, use it to search the base classes.
4045  TStreamerElement* base_element = 0;
4046  TBaseClass* base = 0;
4047  TClass* base_cl = 0;
4048  Int_t base_offset = 0;
4049  Int_t local_offset = 0;
4050  TIter nextb(fClass->GetListOfBases());
4051  // Iterate on list of base classes.
4052  while ((base = (TBaseClass*) nextb())) {
4053  base_cl = TClass::GetClass(base->GetName());
4054  base_element = (TStreamerElement*) fElements->FindObject(base->GetName());
4055  if (!base_cl || !base_element) {
4056  continue;
4057  }
4058  base_offset = base_element->GetOffset();
4059  element = ((TStreamerInfo*)base_cl->GetStreamerInfo())->GetStreamerElement(datamember, local_offset);
4060  if (element) {
4061  offset = base_offset + local_offset;
4062  return element;
4063  }
4064  }
4065  } else {
4066  // Our class's dictionary is not loaded. Search through the base class streamer elements.
4067  TIter next(fElements);
4068  TStreamerElement* curelem = 0;
4069  while ((curelem = (TStreamerElement*) next())) {
4070  if (curelem->InheritsFrom(TStreamerBase::Class())) {
4071  TClass* baseClass = curelem->GetClassPointer();
4072  if (!baseClass) {
4073  continue;
4074  }
4075  Int_t base_offset = curelem->GetOffset();
4076  Int_t local_offset = 0;
4077  TStreamerInfo *baseInfo;
4078  if (baseClass->Property() & kIsAbstract) {
4079  baseInfo = (TStreamerInfo*)baseClass->GetStreamerInfoAbstractEmulated();
4080  } else {
4081  baseInfo = (TStreamerInfo*)baseClass->GetStreamerInfo();
4082  }
4083  if (baseInfo) element = baseInfo->GetStreamerElement(datamember, local_offset);
4084  if (element) {
4085  offset = base_offset + local_offset;
4086  return element;
4087  }
4088  }
4089  }
4090  }
4091  return 0;
4092 }
4093 
4094 ////////////////////////////////////////////////////////////////////////////////
4095 /// <b>Obsolete</b>: this routine is obsolete and should not longer be used.
4096 ///
4097 /// TStreamerInfo holds two types of data structures
4098 /// - TObjArray* fElements; containing the list of all TStreamerElement
4099 /// objects for this class version.
4100 /// - ULong_t* fElem; containing the preprocessed information
4101 /// by TStreamerInfo::Compile In case consecutive data members
4102 /// are of the same type, the Compile function declares the consecutive
4103 /// elements as one single element in fElems.
4104 ///
4105 /// Example with the class TAttLine:
4106 /// ~~~{.cpp}
4107 /// TClass::GetClass("TAttLine")->GetStreamerInfo()->ls(); produces;
4108 /// StreamerInfo for class: TAttLine, version=1
4109 /// short fLineColor offset= 4 type= 2 line color
4110 /// short fLineStyle offset= 6 type= 2 line style
4111 /// short fLineWidth offset= 8 type= 2 line width
4112 /// i= 0, fLineColor type= 22, offset= 4, len=3, method=0
4113 /// ~~~
4114 /// For I/O implementations (eg. XML) , one has to know the original name
4115 /// of the data member. This function can be used to return a pointer
4116 /// to the original TStreamerElement object corresponding to the j-th
4117 /// element of a compressed array in fElems.
4118 /// Parameters description:
4119 /// - i: the serial number in array fElem
4120 /// - j: the element number in the array of consecutive types
4121 /// In the above example the class TAttLine has 3 consecutive data members
4122 /// of the same type "short". Compile makes one single array of 3 elements.
4123 /// To access the TStreamerElement for the second element
4124 /// of this array, one can call:
4125 /// ~~~{.cpp}
4126 /// auto el = GetStreamerElementReal(0,1);
4127 /// auto membername = el->GetName();
4128 /// ~~~
4129 /// This function is typically called from TBuffer, TXmlBuffer.
4130 
4132 {
4133  ::Obsolete("TStreamerInfo::GetStreamerElementReal", "v5-34-20", "v6-00-02");
4134 
4135  if (i < 0 || i >= fNdata) return 0;
4136  if (j < 0) return 0;
4137  if (!fElements) return 0;
4138  TStreamerElement *se = (TStreamerElement*)fCompOpt[i]->fElem;
4139  if (!se) return 0;
4140  Int_t nelems = fElements->GetEntriesFast();
4141  for (Int_t ise=0;ise < nelems;ise++) {
4142  if (se != (TStreamerElement*)fElements->UncheckedAt(ise)) continue;
4143  if (ise+j >= nelems) return 0;
4144  return (TStreamerElement*)fElements->UncheckedAt(ise+j);
4145  }
4146  return 0;
4147 }
4148 
4149 ////////////////////////////////////////////////////////////////////////////////
4150 /// Get the value from inside a collection.
4151 
4152 template <typename T>
4154 {
4155  if (type>=kConv && type<kSTL) {
4156  type -= kConv;
4157  }
4158  switch (type) {
4159  // basic types
4160  case kBool: {Bool_t *val = (Bool_t*)ladd; return T(*val);}
4161  case kChar: {Char_t *val = (Char_t*)ladd; return T(*val);}
4162  case kShort: {Short_t *val = (Short_t*)ladd; return T(*val);}
4163  case kInt: {Int_t *val = (Int_t*)ladd; return T(*val);}
4164  case kLong: {Long_t *val = (Long_t*)ladd; return T(*val);}
4165  case kLong64: {Long64_t *val = (Long64_t*)ladd; return T(*val);}
4166  case kFloat: {Float_t *val = (Float_t*)ladd; return T(*val);}
4167  case kFloat16: {Float_t *val = (Float_t*)ladd; return T(*val);}
4168  case kDouble: {Double_t *val = (Double_t*)ladd; return T(*val);}
4169  case kDouble32: {Double_t *val = (Double_t*)ladd; return T(*val);}
4170  case kUChar: {UChar_t *val = (UChar_t*)ladd; return T(*val);}
4171  case kUShort: {UShort_t *val = (UShort_t*)ladd; return T(*val);}
4172  case kUInt: {UInt_t *val = (UInt_t*)ladd; return T(*val);}
4173  case kULong: {ULong_t *val = (ULong_t*)ladd; return T(*val);}
4174 #if defined(_MSC_VER) && (_MSC_VER <= 1200)
4175  case kULong64: {Long64_t *val = (Long64_t*)ladd; return T(*val);}
4176 #else
4177  case kULong64: {ULong64_t *val= (ULong64_t*)ladd; return T(*val);}
4178 #endif
4179  case kBits: {UInt_t *val = (UInt_t*)ladd; return T(*val);}
4180 
4181  // array of basic types array[8]
4182  case kOffsetL + kBool: {Bool_t *val = (Bool_t*)ladd; return T(val[k]);}
4183  case kOffsetL + kChar: {Char_t *val = (Char_t*)ladd; return T(val[k]);}
4184  case kOffsetL + kShort: {Short_t *val = (Short_t*)ladd; return T(val[k]);}
4185  case kOffsetL + kInt: {Int_t *val = (Int_t*)ladd; return T(val[k]);}
4186  case kOffsetL + kLong: {Long_t *val = (Long_t*)ladd; return T(val[k]);}
4187  case kOffsetL + kLong64: {Long64_t *val = (Long64_t*)ladd; return T(val[k]);}
4188  case kOffsetL + kFloat: {Float_t *val = (Float_t*)ladd; return T(val[k]);}
4189  case kOffsetL + kFloat16: {Float_t *val = (Float_t*)ladd; return T(val[k]);}
4190  case kOffsetL + kDouble: {Double_t *val = (Double_t*)ladd; return T(val[k]);}
4191  case kOffsetL + kDouble32:{Double_t *val = (Double_t*)ladd; return T(val[k]);}
4192  case kOffsetL + kUChar: {UChar_t *val = (UChar_t*)ladd; return T(val[k]);}
4193  case kOffsetL + kUShort: {UShort_t *val = (UShort_t*)ladd; return T(val[k]);}
4194  case kOffsetL + kUInt: {UInt_t *val = (UInt_t*)ladd; return T(val[k]);}
4195  case kOffsetL + kULong: {ULong_t *val = (ULong_t*)ladd; return T(val[k]);}
4196 #if defined(_MSC_VER) && (_MSC_VER <= 1200)
4197  case kOffsetL + kULong64: {Long64_t *val = (Long64_t*)ladd; return T(val[k]);}
4198 #else
4199  case kOffsetL + kULong64:{ULong64_t *val= (ULong64_t*)ladd; return T(val[k]);}
4200 #endif
4201 
4202 #define READ_ARRAY(TYPE_t) \
4203  { \
4204  Int_t sub_instance, index; \
4205  Int_t instance = k; \
4206  if (len) { \
4207  index = instance / len; \
4208  sub_instance = instance % len; \
4209  } else { \
4210  index = instance; \
4211  sub_instance = 0; \
4212  } \
4213  TYPE_t **val =(TYPE_t**)(ladd); \
4214  return T((val[sub_instance])[index]); \
4215  }
4216 
4217  // pointer to an array of basic types array[n]
4221  case kOffsetP + kInt_t: READ_ARRAY(Int_t)
4224  case kOffsetP + kFloat16_t:
4226  case kOffsetP + kDouble32_t:
4232 #if defined(_MSC_VER) && (_MSC_VER <= 1200)
4234 #else
4236 #endif
4237 
4238  // array counter //[n]
4239  case kCounter: {Int_t *val = (Int_t*)ladd; return T(*val);}
4240  }
4241  return 0;
4242 }
4243 
4244 
4245 
4246 template Double_t TStreamerInfo::GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const;
4247 template Long64_t TStreamerInfo::GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const;
4248 template LongDouble_t TStreamerInfo::GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const;
4249 
4250 ////////////////////////////////////////////////////////////////////////////////
4251 /// Return value of element i in object at pointer.
4252 /// The function may be called in two ways:
4253 /// - method1 len < 0: i is assumed to be the TStreamerElement number i in StreamerInfo
4254 /// - method2 len >= 0: i is the type, address of variable is directly pointer.
4255 
4256 template <typename T>
4257 T TStreamerInfo::GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const
4258 {
4259  char *ladd;
4260  Int_t atype;
4261  if (len >= 0) {
4262  ladd = pointer;
4263  atype = i;
4264  } else {
4265  if (i < 0) return 0;
4266  ladd = pointer + fCompFull[i]->fOffset;
4267  atype = fCompFull[i]->fNewType;
4268  len = fCompFull[i]->fElem->GetArrayLength();
4269  if (atype == kSTL) {
4270  TClass *newClass = fCompFull[i]->fElem->GetNewClass();
4271  if (newClass == 0) {
4272  newClass = fCompFull[i]->fElem->GetClassPointer();
4273  }
4274  TClass *innerClass = newClass->GetCollectionProxy()->GetValueClass();
4275  if (innerClass) {
4276  return 0; // We don't know which member of the class we would want.
4277  } else {
4278  TVirtualCollectionProxy *proxy = newClass->GetCollectionProxy();
4279  // EDataType is a subset of TStreamerInfo::EReadWrite
4280  atype = (TStreamerInfo::EReadWrite)proxy->GetType();
4281  TVirtualCollectionProxy::TPushPop pop(proxy,ladd);
4282  Int_t nc = proxy->Size();
4283  if (j >= nc) return 0;
4284  char *element_ptr = (char*)proxy->At(j);
4285  return GetTypedValueAux<T>(atype,element_ptr,0,1);
4286  }
4287  }
4288  }
4289  return GetTypedValueAux<T>(atype,ladd,j,len);
4290 }
4291 
4292 ////////////////////////////////////////////////////////////////////////////////
4293 
4294 template Double_t TStreamerInfo::GetTypedValueClones<Double_t>(TClonesArray *clones, Int_t i, Int_t j, int k, Int_t eoffset) const;
4295 template Long64_t TStreamerInfo::GetTypedValueClones(TClonesArray *clones, Int_t i, Int_t j, int k, Int_t eoffset) const;
4296 template LongDouble_t TStreamerInfo::GetTypedValueClones(TClonesArray *clones, Int_t i, Int_t j, int k, Int_t eoffset) const;
4297 
4298 template <typename T>
4300 {
4301  // return value of element i in object number j in a TClonesArray and eventually
4302  // element k in a sub-array.
4303 
4304  Int_t nc = clones->GetEntriesFast();
4305  if (j >= nc) return 0;
4306 
4307  char *pointer = (char*)clones->UncheckedAt(j);
4308  char *ladd = pointer + eoffset + fCompFull[i]->fOffset;
4309  return GetTypedValueAux<T>(fCompFull[i]->fType,ladd,k,((TStreamerElement*)fCompFull[i]->fElem)->GetArrayLength());
4310 }
4311 
4312 template Double_t TStreamerInfo::GetTypedValueSTL(TVirtualCollectionProxy *cont, Int_t i, Int_t j, int k, Int_t eoffset) const;
4313 template Long64_t TStreamerInfo::GetTypedValueSTL(TVirtualCollectionProxy *cont, Int_t i, Int_t j, int k, Int_t eoffset) const;
4314 template LongDouble_t TStreamerInfo::GetTypedValueSTL(TVirtualCollectionProxy *cont, Int_t i, Int_t j, int k, Int_t eoffset) const;
4315 
4316 ////////////////////////////////////////////////////////////////////////////////
4317 /// Return value of element i in object number j in a TClonesArray and eventually
4318 /// element k in a sub-array.
4319 
4320 template <typename T>
4322 {
4323  Int_t nc = cont->Size();
4324  if (j >= nc) return 0;
4325 
4326  char *pointer = (char*)cont->At(j);
4327  char *ladd = pointer + eoffset + fCompFull[i]->fOffset;
4328  return GetTypedValueAux<T>(fCompFull[i]->fType,ladd,k,((TStreamerElement*)fCompFull[i]->fElem)->GetArrayLength());
4329 }
4330 
4331 template Double_t TStreamerInfo::GetTypedValueSTLP(TVirtualCollectionProxy *cont, Int_t i, Int_t j, int k, Int_t eoffset) const;
4332 template Long64_t TStreamerInfo::GetTypedValueSTLP(TVirtualCollectionProxy *cont, Int_t i, Int_t j, int k, Int_t eoffset) const;
4333 template LongDouble_t TStreamerInfo::GetTypedValueSTLP(TVirtualCollectionProxy *cont, Int_t i, Int_t j, int k, Int_t eoffset) const;
4334 
4335 ////////////////////////////////////////////////////////////////////////////////
4336 /// Return value of element i in object number j in a TClonesArray and eventually
4337 /// element k in a sub-array.
4338 
4339 template <typename T>
4341 {
4342  Int_t nc = cont->Size();
4343 
4344  if (j >= nc) return 0;
4345 
4346  char **ptr = (char**)cont->At(j);
4347  char *pointer = *ptr;
4348 
4349  char *ladd = pointer + eoffset + fCompFull[i]->fOffset;
4350  return GetTypedValueAux<T>(fCompFull[i]->fType,ladd,k,((TStreamerElement*)fCompFull[i]->fElem)->GetArrayLength());
4351 }
4352 
4353 ////////////////////////////////////////////////////////////////////////////////
4354 /// Insert new members as expressed in the array of TSchemaRule(s).
4355 
4356 void TStreamerInfo::InsertArtificialElements(std::vector<const ROOT::TSchemaRule*> &rules)
4357 {
4358  if (rules.empty()) return;
4359 
4360  TIter next(fElements);
4361  UInt_t count = 0;
4362 
4363  for(auto rule : rules) {
4364  if( rule->IsRenameRule() || rule->IsAliasRule() )
4365  continue;
4366  next.Reset();
4367  TStreamerElement *element;
4368  while ((element = (TStreamerElement*) next())) {
4369  if ( rule->HasTarget( element->GetName() ) ) {
4370 
4371  // Check whether this is an 'attribute' rule.
4372  if ( rule->GetAttributes()[0] != 0 ) {
4373  TString attr( rule->GetAttributes() );
4374  attr.ToLower();
4375  if (attr.Contains("owner")) {
4376  if (attr.Contains("notowner")) {
4378  } else {
4380  }
4381  }
4382 
4383  }
4384  break;
4385  }
4386  }
4387 
4388  // NOTE: Before adding the rule we should check that the source do
4389  // existing in this StreamerInfo.
4390  const TObjArray *sources = rule->GetSource();
4391  TIter input(sources);
4392  TObject *src;
4393  while((src = input())) {
4394  if ( !GetElements()->FindObject(src->GetName()) ) {
4395  // Missing source.
4396 #if 0 // Don't warn about not activating the rule. If don't warn the user can
4397  // have more flexibility in specifying when the rule applies and relying
4398  // on both the version number *and* the presence of the source members.
4399  // Activating this warning would for example mean that we need to carefully
4400  // tweak $ROOTSYS/etc/class.rules.
4401  TString ruleStr;
4402  rule->AsString(ruleStr);
4403  Warning("InsertArtificialElements","For class %s in StreamerInfo %d is missing the source data member %s when trying to apply the rule:\n %s",
4404  GetName(),GetClassVersion(),src->GetName(),ruleStr.Data());
4405  rule = 0;
4406 #endif
4407  break;
4408  }
4409  }
4410 
4411  if (!rule) continue;
4412 
4413  TStreamerArtificial *newel;
4414  typedef std::vector<TStreamerArtificial*> vec_t;
4415  vec_t toAdd;
4416 
4417  if (rule->GetTarget()==0) {
4418  TString newName;
4419  newName.Form("%s_rule%d",fClass->GetName(),count);
4420  newel = new TStreamerArtificial(newName,"",
4421  fClass->GetDataMemberOffset(newName),
4423  "void");
4425  newel->SetReadFunc( rule->GetReadFunctionPointer() );
4426  newel->SetReadRawFunc( rule->GetReadRawFunctionPointer() );
4427  toAdd.push_back(newel);
4428  } else {
4429  toAdd.reserve(rule->GetTarget()->GetEntries());
4430  TObjString * objstr = (TObjString*)(rule->GetTarget()->At(0));
4431  if (objstr) {
4432  TString newName = objstr->String();
4433  TString realDataName;
4434  if ( TDataMember* dm = fClass->GetDataMember( newName ) ) {
4435  TRealData::GetName(realDataName,dm);
4436  newel = new TStreamerArtificial(realDataName,"",
4437  fClass->GetDataMemberOffset(newName),
4439  fClass->GetDataMember( newName )->GetTypeName());
4440  newel->SetReadFunc( rule->GetReadFunctionPointer() );
4441  newel->SetReadRawFunc( rule->GetReadRawFunctionPointer() );
4442  toAdd.push_back(newel);
4443  } else {
4444  // This would be a completely new member (so it would need to be cached)
4445  // TOBEDONE
4446  }
4447  for(Int_t other = 1; other < rule->GetTarget()->GetEntries(); ++other) {
4448  objstr = (TObjString*)(rule->GetTarget()->At(other));
4449  if (objstr) {
4450  newName = objstr->String();
4451  if ( TDataMember* dm = fClass->GetDataMember( newName ) ) {
4452  TRealData::GetName(realDataName,dm);
4453  newel = new TStreamerArtificial(realDataName,"",
4454  fClass->GetDataMemberOffset(newName),
4456  fClass->GetDataMember( newName )->GetTypeName());
4457  toAdd.push_back(newel);
4458  }
4459  }
4460  }
4461  } // For each target of the rule
4462  }
4463  // Now find we with need to add them
4464  TIter s_iter(rule->GetSource());
4465  Int_t loc = -1;
4466  while( TObjString *s = (TObjString*)s_iter() ) {
4467  for(Int_t i = fElements->GetLast(); i >= 0 && (i+1) >= loc; --i) {
4468  if (s->String() == fElements->UncheckedAt(i)->GetName()) {
4469  if (loc == -1 || (i+1)>loc) {
4470  loc = i+1;
4471  }
4472  }
4473  }
4474  }
4475  if (loc == -1) {
4476  // Verify if the last one is not 'skipped'.
4477  for(Int_t i = fElements->GetLast(); i >= 0 && (i+1) >= loc; --i) {
4478  if ( ((TStreamerElement*)fElements->UncheckedAt(i))->GetNewType() != -2 ) {
4479  break;
4480  }
4481  loc = i;
4482  }
4483  }
4484  if (loc == -1) {
4485  for(vec_t::iterator iter = toAdd.begin(); iter != toAdd.end(); ++iter) {
4486  fElements->Add(*iter);
4487  }
4488  } else {
4489  R__TObjArray_InsertAt(fElements, toAdd, loc);
4490  }
4491  } // None of the target of the rule are on file.
4492 }
4493 
4494 ////////////////////////////////////////////////////////////////////////////////
4495 /// List the TStreamerElement list and also the precomputed tables
4496 /// if option contains the string "incOrig", also prints the original
4497 /// (non-optimized elements in the list of compiled elements.
4498 
4499 void TStreamerInfo::ls(Option_t *option) const
4500 {
4501  if (fClass && (fName != fClass->GetName())) {
4502  if (fClass->IsVersioned()) {
4503  Printf("\nStreamerInfo for conversion to %s from: %s, version=%d, checksum=0x%x",fClass->GetName(),GetName(),fClassVersion,GetCheckSum());
4504  } else {
4505  Printf("\nStreamerInfo for conversion to %s from: %s, checksum=0x%x",fClass->GetName(),GetName(),GetCheckSum());
4506  }
4507  } else {
4508  if (!fClass || fClass->IsVersioned()) {
4509  Printf("\nStreamerInfo for class: %s, version=%d, checksum=0x%x",GetName(),fClassVersion,GetCheckSum());
4510  } else {
4511  Printf("\nStreamerInfo for class: %s, checksum=0x%x",GetName(),GetCheckSum());
4512  }
4513  }
4514 
4515  if (fElements) {
4516  TIter next(fElements);
4517  TObject *obj;
4518  while ((obj = next()))
4519  obj->ls(option);
4520  }
4521  if (strstr(option,"full") != 0) {
4522  for (Int_t i=0; i < fNfulldata; ++i) {
4523  TStreamerElement *element = (TStreamerElement*)fCompFull[i]->fElem;
4524  TString sequenceType;
4525  element->GetSequenceType(sequenceType);
4526  // by definition of the loop (i+1) <= fNdata
4527  if (sequenceType.Length()) {
4528  sequenceType.Prepend(" [");
4529  sequenceType += "]";
4530  }
4531  Printf(" i=%2d, %-15s type=%3d, offset=%3d, len=%d, method=%ld%s",
4532  i,element->GetName(),fCompFull[i]->fType,fCompFull[i]->fOffset,fCompFull[i]->fLength,fCompFull[i]->fMethod,
4533  sequenceType.Data());
4534  }
4535 
4536  } else {
4537  Bool_t wantOrig = strstr(option,"incOrig") != 0;
4538  Bool_t optimized = kFALSE;
4539  for (Int_t i=0,j=0;i < fNdata;++i,++j) {
4540  TStreamerElement *element = (TStreamerElement*)fCompOpt[i]->fElem;
4541  TString sequenceType;
4542  element->GetSequenceType(sequenceType);
4543  // by definition of the loop (i+1) <= fNdata
4545  if (optimized) {
4546  // This was optimized.
4547  if (sequenceType.Length() != 0) {
4548  sequenceType += ',';
4549  }
4550  sequenceType += "optimized";
4551  }
4552  if (sequenceType.Length()) {
4553  sequenceType.Prepend(" [");
4554  sequenceType += "]";
4555  }
4556  Printf(" i=%2d, %-15s type=%3d, offset=%3d, len=%d, method=%ld%s",
4557  i,element->GetName(),fCompOpt[i]->fType,fCompOpt[i]->fOffset,fCompOpt[i]->fLength,fCompOpt[i]->fMethod,
4558  sequenceType.Data());
4559  if (optimized && wantOrig) {
4560  Bool_t done;
4561  do {
4562  element = (TStreamerElement*)fCompFull[j]->fElem;
4563  element->GetSequenceType(sequenceType);
4564  if (sequenceType.Length()) {
4565  sequenceType.Prepend(" [");
4566  sequenceType += "]";
4567  }
4568  Printf(" j=%2d, %-15s type=%3d, offset=%3d, len=%d, method=%ld%s",
4569  j,element->GetName(),fCompFull[j]->fType,fCompFull[j]->fOffset,fCompFull[j]->fLength,fCompFull[j]->fMethod,
4570  sequenceType.Data());
4571  ++j;
4572  done = j >= fNfulldata || ( (i+1 < fNdata) && fCompOpt[i+1]->fElem == fCompFull[j+1]->fElem );
4573  } while (!done);
4574 
4575  }
4576  }
4577  }
4578 }
4579 
4580 ////////////////////////////////////////////////////////////////////////////////
4581 /// An emulated object is created at address obj, if obj is null we
4582 /// allocate memory for the object.
4583 
4584 void* TStreamerInfo::New(void *obj)
4585 {
4586  //???FIX ME: What about varying length array elements?
4587 
4588  char* p = (char*) obj;
4589 
4590  TIter next(fElements);
4591 
4592  if (!p) {
4593  // Allocate and initialize the memory block.
4594  p = new char[fSize];
4595  memset(p, 0, fSize);
4596  }
4597 
4598  next.Reset();
4599  TStreamerElement* element = (TStreamerElement*) next();
4600 
4601  for (; element; element = (TStreamerElement*) next()) {
4602 
4603  // Skip elements which have not been allocated memory.
4604  if (element->GetOffset() == kMissing) {
4605  continue;
4606  }
4607 
4608  // Skip elements for which we do not have any class
4609  // information. FIXME: Document how this could happen.
4610  TClass* cle = element->GetClassPointer();
4611  if (!cle) {
4612  continue;
4613  }
4614 
4615  char* eaddr = p + element->GetOffset();
4616  Int_t etype = element->GetType();
4617 
4618  //cle->GetStreamerInfo(); //necessary in case "->" is not specified
4619 
4620  switch (etype) {
4621 
4622  case kAnyP:
4623  case kObjectP:
4624  case kSTLp:
4625  {
4626  // Initialize array of pointers with null pointers.
4627  char** r = (char**) eaddr;
4628  Int_t len = element->GetArrayLength();
4629  for (Int_t i = 0; i < len; ++i) {
4630  r[i] = 0;
4631  }
4632  }
4633  break;
4634 
4635  case kObjectp:
4636  case kAnyp:
4637  {
4638  // If the option "->" is given in the data member comment field
4639  // it is assumed that the object exists before reading data in,
4640  // so we create an object.
4641  if (cle != TClonesArray::Class()) {
4642  void** r = (void**) eaddr;
4643  *r = cle->New();
4644  } else {
4645  // In the case of a TClonesArray, the class name of
4646  // the contained objects must be specified in the
4647  // data member comment in this format:
4648  // TClonesArray* myVar; //->(className)
4649  const char* title = element->GetTitle();
4650  const char* bracket1 = strrchr(title, '(');
4651  const char* bracket2 = strrchr(title, ')');
4652  if (bracket1 && bracket2 && (bracket2 != (bracket1 + 1))) {
4653  Int_t len = bracket2 - (bracket1 + 1);
4654  char* clonesClass = new char[len+1];
4655  clonesClass[0] = '\0';
4656  strncat(clonesClass, bracket1 + 1, len);
4657  void** r = (void**) eaddr;
4658  *r = (void*) new TClonesArray(clonesClass);
4659  delete[] clonesClass;
4660  } else {
4661  //Warning("New", "No class name found for TClonesArray initializer in data member comment (expected \"//->(className)\"");
4662  void** r = (void**) eaddr;
4663  *r = (void*) new TClonesArray();
4664  }
4665  }
4666  }
4667  break;
4668 
4669  case kBase:
4670  {
4671  if (cle->Property() & kIsAbstract) {
4673  if (einfo) einfo->New(eaddr);
4674  } else {
4675  cle->New(eaddr);
4676  }
4677  break;
4678  }
4679  case kObject:
4680  case kAny:
4681  case kTObject:
4682  case kTString:
4683  case kTNamed:
4684  {
4685  cle->New(eaddr);
4686  }
4687  break;
4688 
4689  case kSTL:
4690  {
4691  if (strcmp(element->GetName(),"This")==0 &&
4692  !cle->GetCollectionProxy()) {
4693  // missing information, avoid infinite loop
4694  // by doing nothing ....
4695  } else {
4696  cle->New(eaddr);
4697  }
4698  }
4699  break;
4700 
4701  case kObject + kOffsetL:
4702  case kAny + kOffsetL:
4703  case kTObject + kOffsetL:
4704  case kTString + kOffsetL:
4705  case kTNamed + kOffsetL:
4706  case kSTL + kOffsetL:
4707  {
4708  Int_t size = cle->Size();
4709  char* r = eaddr;
4710  Int_t len = element->GetArrayLength();
4711  for (Int_t i = 0; i < len; ++i, r += size) {
4712  cle->New(r);
4713  }
4714  }
4715  break;
4716 
4717  } // switch etype
4718  } // for TIter next(fElements)
4719 
4720  for(int nbase = 0; nbase < fNVirtualInfoLoc; ++nbase) {
4721  *(TStreamerInfo**)(p + fVirtualInfoLoc[nbase]) = this;
4722  }
4723  ++fLiveCount;
4724  return p;
4725 }
4726 
4727 ////////////////////////////////////////////////////////////////////////////////
4728 /// An array of emulated objects is created at address ary, if ary is null,
4729 /// we allocate memory for the array.
4730 
4731 void* TStreamerInfo::NewArray(Long_t nElements, void *ary)
4732 {
4733  if (fClass == 0) {
4734  Error("NewArray", "TClass pointer is null!");
4735  return 0;
4736  }
4737 
4738  Int_t size = fClass->Size();
4739 
4740  char* p = (char*) ary;
4741 
4742  if (!p) {
4743  Long_t len = nElements * size + sizeof(Long_t)*2;
4744  p = new char[len];
4745  memset(p, 0, len);
4746  }
4747 
4748  // Store the array cookie
4749  Long_t* r = (Long_t*) p;
4750  r[0] = size;
4751  r[1] = nElements;
4752  char* dataBegin = (char*) &r[2];
4753 
4754  // Do a placement new for each element.
4755  p = dataBegin;
4756  for (Long_t cnt = 0; cnt < nElements; ++cnt) {
4757  New(p);
4758  p += size;
4759  } // for nElements
4760 
4761  return dataBegin;
4762 }
4763 
4764 
4765 #define DeleteBasicPointer(addr,element,name) \
4766  { \
4767  name **f = (name**)(addr); \
4768  int n = element->GetArrayLength() ? element->GetArrayLength() : 1;\
4769  for(int j=0;j<n;j++) { \
4770  delete [] f[j]; \
4771  f[j] = 0; \
4772  } \
4773  }
4774 
4775 ////////////////////////////////////////////////////////////////////////////////
4776 /// Internal part of the destructor.
4777 /// Destruct each of the datamembers in the same order
4778 /// as the implicit destructor would.
4779 
4780 void TStreamerInfo::DestructorImpl(void* obj, Bool_t dtorOnly)
4781 {
4782  R__ASSERT(obj != 0);
4783 
4784  char *p = (char*)obj;
4785 
4786  Int_t nelements = fElements->GetEntriesFast();
4787  //for (; ele; ele = (TStreamerElement*) next())
4788  for (Int_t elenum = nelements - 1; elenum >= 0; --elenum) {
4790  if (ele->GetOffset() == kMissing) continue;
4791  char* eaddr = p + ele->GetOffset();
4792 
4793 
4794  Int_t etype = ele->GetType();
4795 
4796  switch(etype) {
4812  case TStreamerInfo::kCharStar: DeleteBasicPointer(eaddr,ele,Char_t); continue;
4813  }
4814 
4815 
4816 
4817  TClass* cle = ele->GetClassPointer();
4818  if (!cle) continue;
4819 
4820 
4821  if (etype == kObjectp || etype == kAnyp) {
4822  // Destroy an array of pre-allocated objects.
4823  Int_t len = ele->GetArrayLength();
4824  if (!len) {
4825  len = 1;
4826  }
4827  void** r = (void**) eaddr;
4828  for (Int_t j = len - 1; j >= 0; --j) {
4829  if (r[j]) {
4830  cle->Destructor(r[j]);
4831  r[j] = 0;
4832  }
4833  }
4834  }
4835 
4836  if ((etype == kObjectP || etype == kAnyP || etype == kSTLp) && !ele->TestBit(TStreamerElement::kDoNotDelete)) {
4837  // Destroy an array of pointers to not-pre-allocated objects.
4838  Int_t len = ele->GetArrayLength();
4839  if (!len) {
4840  len = 1;
4841  }
4842  void** r = (void**) eaddr;
4843  for (Int_t j = len - 1; j >= 0; --j) {
4844  if (r[j]) {
4845  cle->Destructor(r[j]);
4846  r[j] = 0;
4847  }
4848  }
4849  }
4850 
4851  if (etype == kBase) {
4852  if (cle->Property() & kIsAbstract) {
4854  if (einfo) einfo->Destructor(eaddr, kTRUE);
4855  } else {
4856  cle->Destructor(eaddr, kTRUE);
4857  }
4858  }
4859 
4860  if (etype == kObject || etype == kAny ||
4861  etype == kTObject || etype == kTString || etype == kTNamed) {
4862  // A data member is destroyed, but not deleted.
4863  cle->Destructor(eaddr, kTRUE);
4864  }
4865 
4866  if (etype == kSTL) {
4867  // A data member is destroyed, but not deleted.
4869  if (!pr) {
4870  if (strcmp(ele->GetName(),"This")==0) {
4871  // missing information, avoid infinite loop
4872  // by doing nothing ....
4873  } else {
4874  cle->Destructor(eaddr, kTRUE);
4875  }
4876  } else {
4878  TVirtualCollectionProxy::TPushPop env(cle->GetCollectionProxy(), eaddr); // used for both this 'clear' and the 'clear' inside destructor.
4879  cle->GetCollectionProxy()->Clear(); // empty the collection without deleting the pointer
4880  pr->Destructor(eaddr, kTRUE);
4881  } else {
4882  pr->Destructor(eaddr, kTRUE);
4883  }
4884  }
4885  }
4886 
4887  if (etype == kObject + kOffsetL || etype == kAny + kOffsetL ||
4888  etype == kTObject + kOffsetL || etype == kTString + kOffsetL ||
4889  etype == kTNamed + kOffsetL || etype == kSTL + kOffsetL) {
4890  // For a data member which is an array of objects, we
4891  // destroy the objects, but do not delete them.
4892  Int_t len = ele->GetArrayLength();
4893  Int_t size = cle->Size();
4894  char* r = eaddr + (size * (len - 1));
4895  for (Int_t j = len - 1; j >= 0; --j, r -= size) {
4896  cle->Destructor(r, kTRUE);
4897  }
4898  }
4899  } // iter over elements
4900 
4901  if (!dtorOnly) {
4902  delete[] p;
4903  }
4904  --fLiveCount;
4905 }
4906 
4907 ////////////////////////////////////////////////////////////////////////////////
4908 /// Emulated destructor for this class.
4909 ///
4910 /// An emulated object is destroyed at address p.
4911 /// Destruct each of the datamembers in the same order
4912 /// as the implicit destructor would.
4913 
4914 void TStreamerInfo::Destructor(void* obj, Bool_t dtorOnly)
4915 {
4916  // Do nothing if passed a null pointer.
4917  if (obj == 0) return;
4918 
4919  char* p = (char*) obj;
4920 
4921  if (!dtorOnly && fNVirtualInfoLoc) {
4922  // !dtorOnly is used to filter out the case where this is called for
4923  // a base class or embedded object of the outer most class.
4924  TStreamerInfo *allocator = *(TStreamerInfo**)(p + fVirtualInfoLoc[0]);
4925  if (allocator != this) {
4926 
4927  Int_t baseoffset = allocator->GetClass()->GetBaseClassOffset(GetClass());
4928 
4929  p -= baseoffset;
4930  allocator->DestructorImpl(p, kFALSE);
4931  return;
4932  }
4933  }
4934  DestructorImpl(p, dtorOnly);
4935 }
4936 
4937 ////////////////////////////////////////////////////////////////////////////////
4938 /// Destroy an array of emulated objects, with optional delete.
4939 
4940 void TStreamerInfo::DeleteArray(void* ary, Bool_t dtorOnly)
4941 {
4942  // Do nothing if passed a null pointer.
4943  if (ary == 0) return;
4944 
4945  //???FIX ME: What about varying length arrays?
4946 
4947  Long_t* r = (Long_t*) ary;
4948  Long_t arrayLen = r[-1];
4949  Long_t size = r[-2];
4950  char* memBegin = (char*) &r[-2];
4951 
4952  char* p = ((char*) ary) + ((arrayLen - 1) * size);
4953  for (Long_t cnt = 0; cnt < arrayLen; ++cnt, p -= size) {
4954  // Destroy each element, but do not delete it.
4955  Destructor(p, kTRUE);
4956  } // for arrayItemSize
4957 
4958  if (!dtorOnly) {
4959  delete[] memBegin;
4960  }
4961 }
4962 
4963 ////////////////////////////////////////////////////////////////////////////////
4964 /// print value of element i in object at pointer
4965 /// The function may be called in two ways:
4966 /// -method1 len < 0
4967 /// i is assumed to be the TStreamerElement number i in StreamerInfo
4968 /// -method2 len >= 0
4969 /// i is the type
4970 /// address of variable is directly pointer.
4971 /// len is the number of elements to be printed starting at pointer.
4972 
4973 void TStreamerInfo::PrintValue(const char *name, char *pointer, Int_t i, Int_t len, Int_t lenmax) const
4974 {
4975  char *ladd;
4976  Int_t atype,aleng;
4977  printf(" %-15s = ",name);
4978 
4979  TStreamerElement * aElement = 0;
4980  Int_t *count = 0;
4981  if (len >= 0) {
4982  ladd = pointer;
4983  atype = i;
4984  aleng = len;
4985  } else {
4986  if (i < 0) {
4987  if (pointer==0) {
4988  printf("NULL\n");
4989  } else {
4990  const static TClassRef stringClass("string");
4991  if (fClass == stringClass) {
4992  std::string *st = (std::string*)(pointer);
4993  printf("%s\n",st->c_str());
4994  } else if (fClass == TString::Class()) {
4995  TString *st = (TString*)(pointer);
4996  printf("%s\n",st->Data());
4997  } else {
4998  printf("(%s*)0x%lx\n",GetName(),(ULong_t)pointer);
4999  }
5000  }
5001  return;
5002  }
5003  ladd = pointer + fCompFull[i]->fOffset;
5004  atype = fCompFull[i]->fNewType;
5005  aleng = fCompFull[i]->fLength;
5006  aElement = (TStreamerElement*)fCompFull[i]->fElem;
5007  count = (Int_t*)(pointer+fCompFull[i]->fMethod);
5008  }
5009  if (aleng > lenmax) aleng = lenmax;
5010 
5011  PrintValueAux(ladd,atype,aElement,aleng,count);
5012  printf("\n");
5013 }
5014 
5015 ////////////////////////////////////////////////////////////////////////////////
5016 /// Print value of element i in a TClonesArray.
5017 
5018 void TStreamerInfo::PrintValueClones(const char *name, TClonesArray *clones, Int_t i, Int_t eoffset, Int_t lenmax) const
5019 {
5020  if (!clones) {printf(" %-15s = \n",name); return;}
5021  printf(" %-15s = ",name);
5022  Int_t nc = clones->GetEntriesFast();
5023  if (nc > lenmax) nc = lenmax;
5024 
5025  Int_t offset = eoffset + fCompFull[i]->fOffset;
5026  TStreamerElement *aElement = (TStreamerElement*)fCompFull[i]->fElem;
5027  int aleng = fCompFull[i]->fLength;
5028  if (aleng > lenmax) aleng = lenmax;
5029 
5030  for (Int_t k=0;k < nc;k++) {
5031  char *pointer = (char*)clones->UncheckedAt(k);
5032  char *ladd = pointer+offset;
5033  Int_t *count = (Int_t*)(pointer+fCompFull[i]->fMethod);
5034  PrintValueAux(ladd,fCompFull[i]->fNewType,aElement, aleng, count);
5035  if (k < nc-1) printf(", ");
5036  }
5037  printf("\n");
5038 }
5039 
5040 ////////////////////////////////////////////////////////////////////////////////
5041 /// Print value of element i in a TClonesArray.
5042 
5043 void TStreamerInfo::PrintValueSTL(const char *name, TVirtualCollectionProxy *cont, Int_t i, Int_t eoffset, Int_t lenmax) const
5044 {
5045  if (!cont) {printf(" %-15s = \n",name); return;}
5046  printf(" %-15s = ",name);
5047  Int_t nc = cont->Size();
5048  if (nc > lenmax) nc = lenmax;
5049 
5050  Int_t offset = eoffset + fCompFull[i]->fOffset;
5051  TStreamerElement *aElement = (TStreamerElement*)fCompFull[i]->fElem;
5052  int aleng = fCompFull[i]->fLength;
5053  if (aleng > lenmax) aleng = lenmax;
5054 
5055  for (Int_t k=0;k < nc;k++) {
5056  char *pointer = (char*)cont->At(k);
5057  char *ladd = pointer+offset;
5058  Int_t *count = (Int_t*)(pointer+fCompFull[i]->fMethod);
5059  PrintValueAux(ladd,fCompFull[i]->fNewType,aElement, aleng, count);
5060  if (k < nc-1) printf(", ");
5061  }
5062  printf("\n");
5063 }
5064 
5065 ////////////////////////////////////////////////////////////////////////////////
5066 /// Stream an object of class TStreamerInfo.
5067 
5068 void TStreamerInfo::Streamer(TBuffer &R__b)
5069 {
5070  UInt_t R__s, R__c;
5071  if (R__b.IsReading()) {
5072  Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
5073  fOldVersion = R__v;
5074  if (R__v > 1) {
5075  //R__b.ReadClassBuffer(TStreamerInfo::Class(), this, R__v, R__s, R__c);
5076  R__b.ClassBegin(TStreamerInfo::Class(), R__v);
5077  R__b.ClassMember("TNamed");
5078  TNamed::Streamer(R__b);
5079  fName = TClassEdit::GetLong64_Name( fName.Data() ).c_str();
5080  R__b.ClassMember("fCheckSum","UInt_t");
5081  R__b >> fCheckSum;
5082  R__b.ClassMember("fClassVersion","Int_t");
5083  R__b >> fClassVersion;
5085  R__b.ClassMember("fElements","TObjArray*");
5086  R__b >> fElements;
5088  R__b.SetBufferOffset(R__s+R__c+sizeof(UInt_t));
5092 
5093  if (R__b.GetParent() && R__b.GetVersionOwner() < 50000)
5094  {
5095  // In some older files, the type of the TStreamerElement was not
5096  // as we (now) expect.
5097  Int_t nobjects = fElements->GetEntriesFast();
5098  TClass *basic = TStreamerBasicType::Class();
5099  for (Int_t i = 0; i < nobjects; i++) {
5100  TStreamerElement *el = (TStreamerElement*)fElements->UncheckedAt(i);
5101  TStreamerElement *rel = 0;
5102  if ( el->IsA() == basic ) {
5103  switch (el->GetType()) {
5104  default: break; /* nothing */
5105  case TStreamerInfo::kObject: /*61*/
5106  rel = new TStreamerObject(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5107  break;
5108  case TStreamerInfo::kAny: /*62*/
5109  rel = new TStreamerObjectAny(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5110  break;
5111  case TStreamerInfo::kObjectp: /* 63 */
5112  rel = new TStreamerObjectPointer(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5113  break;
5114  case TStreamerInfo::kObjectP: /* 64 */
5115  rel = new TStreamerObjectPointer(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5116  break;
5117  case TStreamerInfo::kTString: /* 65 */
5118  rel = new TStreamerObject(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5119  break;
5120  }
5121  if (rel) {
5122  (*fElements)[i] = rel;
5123  delete el;
5124  }
5125  }
5126  }
5127  }
5128  return;
5129  }
5130  //====process old versions before automatic schema evolution
5131  TNamed::Streamer(R__b);
5132  fName = TClassEdit::GetLong64_Name( fName.Data() ).c_str();
5133  R__b >> fCheckSum;
5134  R__b >> fClassVersion;
5136  R__b >> fElements;
5137  R__b.CheckByteCount(R__s, R__c, TStreamerInfo::IsA());
5138  } else {
5139  R__c = R__b.WriteVersion(TStreamerInfo::IsA(), kTRUE);
5141  R__b.ClassMember("TNamed");
5142  TNamed::Streamer(R__b);
5143  R__b.ClassMember("fCheckSum","UInt_t");
5144  R__b << fCheckSum;
5145  R__b.ClassMember("fClassVersion","Int_t");
5146  R__b << ((fClassVersion > 0) ? fClassVersion : -fClassVersion);
5147 
5148  //------------------------------------------------------------------------
5149  // Stream only non-artificial streamer elements
5150  //////////////////////////////////////////////////////////////////////////
5151 
5152  R__b.ClassMember("fElements","TObjArray*");
5153 #if NOTYET
5154  if (has_no_artificial_member) {
5155  R__b << fElements;
5156  } else
5157 #endif
5158  {
5160  Int_t nobjects = fElements->GetEntriesFast();
5161  TObjArray store( *fElements );
5162  TStreamerElement *el;
5163  for (Int_t i = 0; i < nobjects; i++) {
5165  if( el != 0 && (el->IsA() == TStreamerArtificial::Class() || el->TestBit(TStreamerElement::kRepeat))) {
5166  fElements->RemoveAt( i );
5167  } else if( el !=0 && (el->TestBit(TStreamerElement::kCache) && !el->TestBit(TStreamerElement::kWrite)) ) {
5168  fElements->RemoveAt( i );
5169  }
5170  }
5171  fElements->Compress();
5172  R__b << fElements;
5173  R__ASSERT(!fElements->IsOwner());
5174  *fElements = store;
5175  }
5177  R__b.SetByteCount(R__c, kTRUE);
5178  }
5179 }
5180 
5181 ////////////////////////////////////////////////////////////////////////////////
5182 /// Mark the classindex of the current file as using this TStreamerInfo.
5183 /// This function is deprecated and its functionality is now done by
5184 /// the overloads of TBuffer::TagStreamerInfo.
5185 
5187 {
5188  if (file) {
5189  // If the value of the atomic is kFALSE (equal to expected), change its value
5190  // to kTRUE and return true. Leave it as it is otherwise and return false.
5191  static std::atomic<Bool_t> onlyonce(kFALSE);
5192  Bool_t expected = kFALSE;
5193  if (onlyonce.compare_exchange_strong(expected,kTRUE)) {
5194  Warning("TagFile","This function is deprecated, use TBuffer::TagStreamerInfo instead");
5195  }
5196  TArrayC *cindex = file->GetClassIndex();
5197  Int_t nindex = cindex->GetSize();
5198  if (fNumber < 0 || fNumber >= nindex) {
5199  Error("TagFile","StreamerInfo: %s number: %d out of range[0,%d] in file: %s",
5200  GetName(),fNumber,nindex,file->GetName());
5201  return;
5202  }
5203  if (cindex->fArray[fNumber] == 0) {
5204  cindex->fArray[0] = 1;
5205  cindex->fArray[fNumber] = 1;
5206  }
5207  }
5208 }
5209 
5210 ////////////////////////////////////////////////////////////////////////////////
5211 
5212 #ifdef DOLOOP
5213 #undef DOLOOP
5214 #endif
5215 #define DOLOOP for (k = 0, pointer = arr[0]; k < narr; pointer = arr[++k])
5216 
5217 namespace {
5218  static void PrintCR(int j,Int_t aleng, UInt_t ltype)
5219  {
5220  if (j == aleng-1) printf("\n");
5221  else {
5222  printf(", ");
5223  if (j%ltype == ltype-1) printf("\n ");
5224  }
5225  }
5226 }
5227 
5228 ////////////////////////////////////////////////////////////////////////////////
5229 /// print value of element in object at pointer, type atype, leng aleng or *count
5230 /// The function may be called in two ways:
5231 /// -method1 len < 0
5232 /// i is assumed to be the TStreamerElement number i in StreamerInfo
5233 /// -method2 len >= 0
5234 /// i is the type
5235 /// address of variable is directly pointer.
5236 /// len is the number of elements to be printed starting at pointer.
5237 
5238 void TStreamerInfo::PrintValueAux(char *ladd, Int_t atype, TStreamerElement *aElement, Int_t aleng, Int_t *count)
5239 {
5240  int j;
5241 
5242  //assert(!((kOffsetP + kChar) <= atype && atype <= (kOffsetP + kBool) && count == 0));
5243  switch (atype) {
5244  // basic types
5245  case kBool: {Bool_t *val = (Bool_t* )ladd; printf("%d" ,*val); break;}
5246  case kChar: {Char_t *val = (Char_t* )ladd; printf("%d" ,*val); break;}
5247  case kShort: {Short_t *val = (Short_t* )ladd; printf("%d" ,*val); break;}
5248  case kInt: {Int_t *val = (Int_t* )ladd; printf("%d" ,*val); break;}
5249  case kLong: {Long_t *val = (Long_t* )ladd; printf("%ld",*val); break;}
5250  case kLong64: {Long64_t *val = (Long64_t* )ladd; printf("%lld",*val); break;}
5251  case kFloat: {Float_t *val = (Float_t* )ladd; printf("%f" ,*val); break;}
5252  case kFloat16: {Float_t *val = (Float_t* )ladd; printf("%f" ,*val); break;}
5253  case kDouble: {Double_t *val = (Double_t* )ladd; printf("%g" ,*val); break;}
5254  case kDouble32: {Double_t *val = (Double_t* )ladd; printf("%g" ,*val); break;}
5255  case kUChar: {UChar_t *val = (UChar_t* )ladd; printf("%u" ,*val); break;}
5256  case kUShort: {UShort_t *val = (UShort_t* )ladd; printf("%u" ,*val); break;}
5257  case kUInt: {UInt_t *val = (UInt_t* )ladd; printf("%u" ,*val); break;}
5258  case kULong: {ULong_t *val = (ULong_t* )ladd; printf("%lu",*val); break;}
5259  case kULong64: {ULong64_t *val = (ULong64_t*)ladd; printf("%llu",*val); break;}
5260  case kBits: {UInt_t *val = (UInt_t* )ladd; printf("%d" ,*val); break;}
5261 
5262  // array of basic types array[8]
5263  case kOffsetL + kBool: {Bool_t *val = (Bool_t* )ladd; for(j=0;j<aleng;j++) { printf("%c " ,val[j]); PrintCR(j,aleng,20); } break;}
5264  case kOffsetL + kChar: {Char_t *val = (Char_t* )ladd; for(j=0;j<aleng;j++) { printf("%c " ,val[j]); PrintCR(j,aleng,20); } break;}
5265  case kOffsetL + kShort: {Short_t *val = (Short_t* )ladd; for(j=0;j<aleng;j++) { printf("%d " ,val[j]); PrintCR(j,aleng,10); } break;}
5266  case kOffsetL + kInt: {Int_t *val = (Int_t* )ladd; for(j=0;j<aleng;j++) { printf("%d " ,val[j]); PrintCR(j,aleng,10); } break;}
5267  case kOffsetL + kLong: {Long_t *val = (Long_t* )ladd; for(j=0;j<aleng;j++) { printf("%ld ",val[j]); PrintCR(j,aleng, 5); } break;}
5268  case kOffsetL + kLong64: {Long64_t *val = (Long64_t* )ladd; for(j=0;j<aleng;j++) { printf("%lld ",val[j]);PrintCR(j,aleng, 5); } break;}
5269  case kOffsetL + kFloat: {Float_t *val = (Float_t* )ladd; for(j=0;j<aleng;j++) { printf("%f " ,val[j]); PrintCR(j,aleng, 5); } break;}
5270  case kOffsetL + kFloat16: {Float_t *val = (Float_t* )ladd; for(j=0;j<aleng;j++) { printf("%f " ,val[j]); PrintCR(j,aleng, 5); } break;}
5271  case kOffsetL + kDouble: {Double_t *val = (Double_t* )ladd; for(j=0;j<aleng;j++) { printf("%g " ,val[j]); PrintCR(j,aleng, 5); } break;}
5272  case kOffsetL + kDouble32:{Double_t *val = (Double_t* )ladd; for(j=0;j<aleng;j++) { printf("%g " ,val[j]); PrintCR(j,aleng, 5); } break;}
5273  case kOffsetL + kUChar: {UChar_t *val = (UChar_t* )ladd; for(j=0;j<aleng;j++) { printf("%u " ,val[j]); PrintCR(j,aleng,20); } break;}
5274  case kOffsetL + kUShort: {UShort_t *val = (UShort_t* )ladd; for(j=0;j<aleng;j++) { printf("%u " ,val[j]); PrintCR(j,aleng,10); } break;}
5275  case kOffsetL + kUInt: {UInt_t *val = (UInt_t* )ladd; for(j=0;j<aleng;j++) { printf("%u " ,val[j]); PrintCR(j,aleng, 5); } break;}
5276  case kOffsetL + kULong: {ULong_t *val = (ULong_t* )ladd; for(j=0;j<aleng;j++) { printf("%lu ",val[j]); PrintCR(j,aleng, 5); } break;}
5277  case kOffsetL + kULong64: {ULong64_t *val = (ULong64_t*)ladd; for(j=0;j<aleng;j++) { printf("%llu ",val[j]);PrintCR(j,aleng, 5); } break;}
5278  case kOffsetL + kBits: {UInt_t *val = (UInt_t* )ladd; for(j=0;j<aleng;j++) { printf("%d " ,val[j]); PrintCR(j,aleng, 5); } break;}
5279 
5280  // pointer to an array of basic types array[n]
5281  case kOffsetP + kBool: {Bool_t **val = (Bool_t** )ladd; for(j=0;j<*count;j++) { printf("%d " ,(*val)[j]); PrintCR(j,aleng,20); } break;}
5282  case kOffsetP + kChar: {Char_t **val = (Char_t** )ladd; for(j=0;j<*count;j++) { printf("%d " ,(*val)[j]); PrintCR(j,aleng,20); } break;}
5283  case kOffsetP + kShort: {Short_t **val = (Short_t** )ladd; for(j=0;j<*count;j++) { printf("%d " ,(*val)[j]); PrintCR(j,aleng,10); } break;}
5284  case kOffsetP + kInt: {Int_t **val = (Int_t** )ladd; for(j=0;j<*count;j++) { printf("%d " ,(*val)[j]); PrintCR(j,aleng,10); } break;}
5285  case kOffsetP + kLong: {Long_t **val = (Long_t** )ladd; for(j=0;j<*count;j++) { printf("%ld ",(*val)[j]); PrintCR(j,aleng, 5); } break;}
5286  case kOffsetP + kLong64: {Long64_t **val = (Long64_t**)ladd; for(j=0;j<*count;j++) { printf("%lld ",(*val)[j]); PrintCR(j,aleng, 5); } break;}
5287  case kOffsetP + kFloat: {Float_t **val = (Float_t** )ladd; for(j=0;j<*count;j++) { printf("%f " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5288  case kOffsetP + kFloat16: {Float_t **val = (Float_t** )ladd; for(j=0;j<*count;j++) { printf("%f " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5289  case kOffsetP + kDouble: {Double_t **val = (Double_t**)ladd; for(j=0;j<*count;j++) { printf("%g " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5290  case kOffsetP + kDouble32:{Double_t **val = (Double_t**)ladd; for(j=0;j<*count;j++) { printf("%g " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5291  case kOffsetP + kUChar: {UChar_t **val = (UChar_t** )ladd; for(j=0;j<*count;j++) { printf("%u " ,(*val)[j]); PrintCR(j,aleng,20); } break;}
5292  case kOffsetP + kUShort: {UShort_t **val = (UShort_t**)ladd; for(j=0;j<*count;j++) { printf("%u " ,(*val)[j]); PrintCR(j,aleng,10); } break;}
5293  case kOffsetP + kUInt: {UInt_t **val = (UInt_t** )ladd; for(j=0;j<*count;j++) { printf("%u " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5294  case kOffsetP + kULong: {ULong_t **val = (ULong_t** )ladd; for(j=0;j<*count;j++) { printf("%lu ",(*val)[j]); PrintCR(j,aleng, 5); } break;}
5295  case kOffsetP + kULong64: {ULong64_t**val = (ULong64_t**)ladd; for(j=0;j<*count;j++){ printf("%llu ",(*val)[j]); PrintCR(j,aleng, 5); } break;}
5296 
5297  // array counter //[n]
5298  case kCounter: {Int_t *val = (Int_t*)ladd; printf("%d",*val); break;}
5299  // char *
5300  case kCharStar:{
5301  char **val = (char**)ladd;
5302  if (*val) printf("%s",*val);
5303  break;
5304  }
5305  // Class * derived from TObject with comment field //->
5306  case kObjectp: {
5307  TObject **obj = (TObject**)(ladd);
5309  printf("(%s*)%lx",el ? el->GetClass()->GetName() : "unknown_type",(Long_t)(*obj));
5310  break;
5311  }
5312 
5313  // Class* derived from TObject
5314  case kObjectP: {
5315  TObject **obj = (TObject**)(ladd);
5317  printf("(%s*)%lx",el ? el->GetClass()->GetName() : "unknown_type",(Long_t)(*obj));
5318  break;
5319  }
5320 
5321  // Class derived from TObject
5322  case kObject: {
5323  TObject *obj = (TObject*)(ladd);
5324  printf("%s",obj->GetName());
5325  break;
5326  }
5327 
5328  // Special case for TString, TObject, TNamed
5329  case kTString: {
5330  TString *st = (TString*)(ladd);
5331  printf("%s",st->Data());
5332  break;
5333  }
5334  case kTObject: {
5335  TObject *obj = (TObject*)(ladd);
5336  printf("%s",obj->GetName());
5337  break;
5338  }
5339  case kTNamed: {
5340  TNamed *named = (TNamed*) (ladd);
5341  printf("%s/%s",named->GetName(),named->GetTitle());
5342  break;
5343  }
5344 
5345  // Class * not derived from TObject with comment field //->
5346  case kAnyp: {
5347  TObject **obj = (TObject**)(ladd);
5349  printf("(%s*)0x%lx",el ? el->GetClass()->GetName() : "unknown_type",(Long_t)(*obj));
5350  break;
5351  }
5352 
5353  // Class* not derived from TObject
5354  case kAnyP: {
5355  TObject **obj = (TObject**)(ladd);
5357  printf("(%s*)0x%lx",el ? el->GetClass()->GetName() : "unknown_type",(Long_t)(*obj));
5358  break;
5359  }
5360  // Any Class not derived from TObject
5361  case kOffsetL + kObjectp:
5362  case kOffsetL + kObjectP:
5363  case kAny: {
5364  printf("printing kAny case (%d)",atype);
5365 // if (aElement) {
5366 // TMemberStreamer *pstreamer = aElement->GetStreamer();
5367 // if (pstreamer == 0) {
5368 // //printf("ERROR, Streamer is null\n");
5369 // //aElement->ls();
5370 // break;
5371 // }
5372 // //(*pstreamer)(b,ladd,0);
5373 // }
5374  break;
5375  }
5376  // Base Class
5377  case kBase: {
5378  printf("printing kBase case (%d)",atype);
5379  //aElement->ReadBuffer(b,pointer);
5380  break;
5381  }
5382 
5383  case kOffsetL + kObject:
5384  case kOffsetL + kTString:
5385  case kOffsetL + kTObject:
5386  case kOffsetL + kTNamed:
5387  case kStreamer: {
5388  printf("printing kStreamer case (%d)",atype);
5389 // TMemberStreamer *pstreamer = aElement->GetStreamer();
5390 // if (pstreamer == 0) {
5391 // //printf("ERROR, Streamer is null\n");
5392 // //aElement->ls();
5393 // break;
5394 // }
5395 // //UInt_t start,count;
5396 // //b.ReadVersion(&start, &count);
5397 // //(*pstreamer)(b,ladd,0);
5398 // //b.CheckByteCount(start,count,IsA());
5399  break;
5400  }
5401 
5402  case kStreamLoop: {
5403  printf("printing kStreamLoop case (%d)",atype);
5404 // TMemberStreamer *pstreamer = aElement->GetStreamer();
5405 // if (pstreamer == 0) {
5406 // //printf("ERROR, Streamer is null\n");
5407 // //aElement->ls();
5408 // break;
5409 // }
5410  //Int_t *counter = (Int_t*)(count);
5411  //UInt_t start,count;
5412  ///b.ReadVersion(&start, &count);
5413  //(*pstreamer)(b,ladd,*counter);
5414  //b.CheckByteCount(start,count,IsA());
5415  break;
5416  }
5417  case kSTL: {
5418  if (aElement) {
5419  static TClassRef stringClass("string");
5420  if (ladd && aElement->GetClass() == stringClass) {
5421  std::string *st = (std::string*)(ladd);
5422  printf("%s",st->c_str());
5423  } else {
5424  printf("(%s*)0x%lx",aElement->GetClass()->GetName(),(Long_t)(ladd));
5425  }
5426  } else {
5427  printf("(unknown_type*)0x%lx",(Long_t)(ladd));
5428  }
5429  break;
5430  }
5431  }
5432 }
5433 
5434 ////////////////////////////////////////////////////////////////////////////////
5435 ///function called by the TClass constructor when replacing an emulated class
5436 ///by the real class
5437 
5438 void TStreamerInfo::Update(const TClass *oldcl, TClass *newcl)
5439 {
5440  TStreamerElement *element;
5441  TIter nextElement(GetElements());
5442  while ((element = (TStreamerElement*)nextElement())) {
5443  element->Update(oldcl,newcl);
5444  }
5445  for (Int_t i=0;i < fNslots;i++) {
5446  fComp[i].Update(oldcl,newcl);
5447  }
5448 }
5449 
5450 ////////////////////////////////////////////////////////////////////////////////
5451 /// Update the TClass pointer cached in this object.
5452 
5454 {
5455  if (fType != -1) {
5456  if (fClass == oldcl)
5457  fClass = newcl;
5458  else if (fClass == 0)
5459  fClass = TClass::GetClass(fClassName);
5460  }
5461 }
5462 
5463 ////////////////////////////////////////////////////////////////////////////////
5464 /// Generate emulated collection proxy for a given class.
5465 
5467 TStreamerInfo::GenEmulatedProxy(const char* class_name, Bool_t silent)
5468 {
5469  return TCollectionProxyFactory::GenEmulatedProxy(class_name, silent);
5470 }
5471 
5472 ////////////////////////////////////////////////////////////////////////////////
5473 /// Generate emulated class streamer for a given collection class.
5474 
5476 TStreamerInfo::GenEmulatedClassStreamer(const char* class_name, Bool_t silent)
5477 {
5478  return TCollectionProxyFactory::GenEmulatedClassStreamer(class_name, silent);
5479 }
5480 
5481 ////////////////////////////////////////////////////////////////////////////////
5482 /// Generate proxy from static functions.
5483 
5485 TStreamerInfo::GenExplicitProxy( const ::ROOT::TCollectionProxyInfo &info, TClass *cl )
5486 {
5488 }
5489 
5490 ////////////////////////////////////////////////////////////////////////////////
5491 /// Generate class streamer from static functions.
5492 
5494 TStreamerInfo::GenExplicitClassStreamer( const ::ROOT::TCollectionProxyInfo &info, TClass *cl )
5495 {
5497 }
Bool_t HasRuleWithSourceClass(const TString &source) const
Return True if we have any rule whose source class is &#39;source&#39;.
const int ndata
Describe Streamer information for one class version.
Definition: TStreamerInfo.h:47
Small helper to read a TBuffer containing a TClonesArray into any valid collection.
Int_t GetOffset(const char *) const
Return the offset of the data member as indicated by this StreamerInfo.
virtual const char * BaseName(const char *pathname)
Base name of a file name. Base name of /user/root is root.
Definition: TSystem.cxx:929
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:51
virtual void * New(void *obj=0)=0
virtual Bool_t IsTransient() const
Return kTRUE if the element represent an entity that is not written to the disk (transient members...
void SetBufferOffset(Int_t offset=0)
Definition: TBuffer.h:90
virtual Int_t GetCollectionType() const =0
virtual void Init(TVirtualStreamerInfo *obj=0)
Setup the element.
Bool_t IsReading() const
Definition: TBuffer.h:83
Int_t fClassVersion
Class version identifier.
Definition: TStreamerInfo.h:97
Bool_t IsForeign() const
Return kTRUE is the class is Foreign (the class does not have a Streamer method). ...
Definition: TClass.cxx:5592
TList * GetListOfBases()
Return list containing the TBaseClass(es) of a class.
Definition: TClass.cxx:3460
static std::atomic< Int_t > fgCount
Number of TStreamerInfo instances.
const char * GetCountClass() const
An array of TObjects.
Definition: TObjArray.h:39
static void R__TObjArray_InsertBefore(TObjArray *arr, TObject *newobj, TObject *oldobj)
const char * GetTypeNameBasic() const
Return type name of this element in case the type name is not a standard basic type, return the basic type name known to CINT.
virtual void ClassBegin(const TClass *, Version_t=-1)=0
T GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const
Return value of element i in object at pointer.
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition: TObject.cxx:899
virtual void SetOffset(Int_t offset)
TString GetTypeName()
Get basic type of typedef, e,g.
Definition: TDataType.cxx:149
Version_t fOldVersion
! Version of the TStreamerInfo object read from the file
ROOT::ESTLType IsSTLCont(std::string_view type)
type : type name: vector<list<classA,allocator>,allocator> result: 0 : not stl container code of cont...
long long Long64_t
Definition: RtypesCore.h:69
virtual Int_t GetProperties() const
static void PrintValueAux(char *ladd, Int_t atype, TStreamerElement *aElement, Int_t aleng, Int_t *count)
print value of element in object at pointer, type atype, leng aleng or *count The function may be cal...
void BuildEmulated(TFile *file)
Create an Emulation TStreamerInfo object.
TStreamerInfoActions::TActionSequence * fWriteMemberWiseVecPtr
! List of write action resulting from the compilation for use in member wise streaming.
short Version_t
Definition: RtypesCore.h:61
TStreamerElement * GetStreamerElement(const char *datamember, Int_t &offset) const
Return the StreamerElement of "datamember" inside our class or any of its base classes.
virtual Bool_t CompareContent(TClass *cl, TVirtualStreamerInfo *info, Bool_t warn, Bool_t complete, TFile *file)=0
const char * GetFullTypeName() const
Get full type description of data member, e,g.: "class TDirectory*".
TLine * line
virtual TClass * GetClass() const =0
Collectable string class.
Definition: TObjString.h:32
Eventhough BIT(13) is taken up by TObject (to preserverse forward compatibility)
float Float_t
Definition: RtypesCore.h:53
Equal to TDataType&#39;s kchar.
virtual void SetSize(Int_t dsize)
return c
const char Option_t
Definition: RtypesCore.h:62
virtual TClass * GetValueClass() const =0
virtual void Delete(Option_t *option="")
Remove all objects from the array AND delete all heap based objects.
Definition: TObjArray.cxx:329
All ROOT classes may have RTTI (run time type identification) support added.
Definition: TDataMember.h:33
TObject * GetParent() const
Return pointer to parent of this buffer.
Definition: TBuffer.cxx:231
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
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
T GetTypedValueSTL(TVirtualCollectionProxy *cont, Int_t i, Int_t j, Int_t k, Int_t eoffset) const
Return value of element i in object number j in a TClonesArray and eventually element k in a sub-arra...
Int_t GetUnitSize() const
Get the sizeof the underlying type of the data member (i.e.
unsigned short UShort_t
Definition: RtypesCore.h:36
Bool_t TestBit(UInt_t f) const
Definition: TObject.h:157
virtual TClass * GetClassPointer() const
Returns a pointer to the TClass of this element.
virtual void SetName(const char *name)
Set the name of the TNamed.
Definition: TNamed.cxx:131
TArrayC * GetClassIndex() const
Definition: TFile.h:195
TStreamerElement * GetStreamerElementReal(Int_t i, Int_t j) const
Obsolete: this routine is obsolete and should not longer be used.
UInt_t GetBaseCheckSum()
TVirtualStreamerInfo * GetStreamerInfo(Int_t version=0) const
returns a pointer to the TVirtualStreamerInfo object for version If the object does not exist...
Definition: TClass.cxx:4368
void Update(const TClass *oldcl, TClass *newcl)
Update the TClass pointer cached in this object.
static TClassStreamer * GenEmulatedClassStreamer(const char *class_name, Bool_t silent)
Generate emulated class streamer for a given collection class.
A ROOT file is a suite of consecutive data records (TKey instances) with a well defined format...
Definition: TFile.h:50
virtual Int_t GetEntries() const
Definition: TCollection.h:92
const char * GetTypeName() const
Get type of data member, e,g.: "class TDirectory*" -> "TDirectory".
Buffer base class used for serializing objects.
Definition: TBuffer.h:42
Bool_t HasInterpreterInfo() const
Definition: TClass.h:374
TClassStreamer * GetStreamer() const
Return the Streamer Class allowing streaming (if any).
Definition: TClass.cxx:2839
virtual void SetTypeName(const char *name)
#define R__ASSERT(e)
Definition: TError.h:98
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:3570
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition: TString.h:582
void SetReadFunc(ROOT::TSchemaRule::ReadFuncPtr_t val)
void ForceWriteInfo(TFile *file, Bool_t force=kFALSE)
Recursively mark streamer infos for writing to a file.
void PrintValueClones(const char *name, TClonesArray *clones, Int_t i, Int_t eoffset, Int_t lenmax=1000) const
Print value of element i in a TClonesArray.
void * New(void *obj=0)
An emulated object is created at address obj, if obj is null we allocate memory for the object...
EUniquePtrOffset
Basic string class.
Definition: TString.h:137
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition: TClass.cxx:2822
Int_t GetArrayLength() const
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
void Reset()
Definition: TClassRef.h:76
virtual void Clear(const char *opt="")=0
const Bool_t kFALSE
Definition: Rtypes.h:92
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
bool IsSTLBitset(const char *type)
Return true is the name is std::bitset<number> or bitset<number>
virtual void SetArrayDim(Int_t dim)
Set number of array dimensions.
ULong_t * fVirtualInfoLoc
![fNVirtualInfoLoc] Location of the pointer to the TStreamerInfo inside the object (when emulated) ...
TString & Prepend(const char *cs)
Definition: TString.h:604
Abstract base class for accessing the data-members of a class.
virtual UInt_t WriteVersion(const TClass *cl, Bool_t useBcnt=kFALSE)=0
TObject * At(Int_t idx) const
Definition: TObjArray.h:167
Int_t GetBaseVersion()
Int_t GetArrayDim() const
const char * Class
Definition: TXMLSetup.cxx:64
TClass * GetActualClass(const void *obj) const
Assuming that obj points to (the part of) an object that is of the type described by this streamerInf...
virtual EDataType GetType() const =0
Bool_t MatchLegacyCheckSum(UInt_t checksum) const
Return true if the checksum passed as argument is one of the checksum value produced by the older che...
void GetSequenceType(TString &type) const
Fill type with the string representation of sequence information including &#39;cached&#39;,&#39;repeat&#39;,&#39;write&#39; or &#39;nodelete&#39;.
virtual void SetMaxIndex(Int_t dim, Int_t max)
set maximum index for array with dimension dim
virtual void ForceWriteInfo(TFile *file, Bool_t force=kFALSE)=0
void Destructor(void *p, Bool_t dtorOnly=kFALSE)
Emulated destructor for this class.
static Proxy_t * GenExplicitProxy(const ::ROOT::TCollectionProxyInfo &info, TClass *cl)
Generate proxy from static functions.
void DeleteArray(void *p, Bool_t dtorOnly=kFALSE)
Destroy an array of emulated objects, with optional delete.
void PrintValue(const char *name, char *pointer, Int_t i, Int_t len, Int_t lenmax=1000) const
print value of element i in object at pointer The function may be called in two ways: -method1 len < ...
void Reset()
Definition: TCollection.h: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
TClass * GetClass() const
Definition: TClassRef.h:75
virtual TObject * FindObject(const char *name) const
Find an object in this list using its name.
Definition: TList.cxx:497
if object in a list can be deleted
Definition: TObject.h:56
void ComputeSize()
Compute total size of all persistent elements of the class.
virtual void Init(TVirtualStreamerInfo *obj=0)
Setup the element.
TStreamerInfoActions::TActionSequence * fReadMemberWise
! List of read action resulting from the compilation for use in member wise streaming.
Int_t fSize
!size of the persistent class
Int_t GetBaseClassOffset(const TClass *toBase, void *address=0, bool isDerivedObject=true)
Definition: TClass.cxx:2717
virtual void ClassMember(const char *, const char *=0, Int_t=-1, Int_t=-1)=0
TObject * Last() const
Return the object in the last filled slot. Returns 0 if no entries.
Definition: TObjArray.cxx:479
Bool_t IsBasic() const
Return true if data member is a basic type, e.g. char, int, long...
virtual Int_t GetClassVersion() const =0
virtual TVirtualCollectionProxy * GenEmulatedProxy(const char *class_name, Bool_t silent)
Generate emulated collection proxy for a given class.
friend class TClonesArray
Definition: TObject.h:198
#define READ_ARRAY(TYPE_t)
Int_t GetVersion() const
Definition: TFile.h:214
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 TClassStreamer * GenEmulatedClassStreamer(const char *class_name, Bool_t silent)
Generate emulated class streamer for a given collection class.
The TNamed class is the base class for all named ROOT classes.
Definition: TNamed.h:33
virtual TVirtualCollectionProxy * GenExplicitProxy(const ::ROOT::Detail::TCollectionProxyInfo &info, TClass *cl)
Generate proxy from static functions.
virtual TObject * FindObject(const char *name) const
Find an object in this collection using its name.
Definition: TObjArray.cxx:396
virtual Int_t GetVersionOwner() const =0
ECheckSum
Definition: TClass.h:102
std::string GetNameForIO(const std::string &templateInstanceName, TClassEdit::EModType mode=TClassEdit::kNone, bool *hasChanged=nullptr)
TVirtualStreamerInfo * GetStreamerInfoAbstractEmulated(Int_t version=0) const
For the case where the requestor class is emulated and this class is abstract, returns a pointer to t...
Definition: TClass.cxx:4451
Long_t Property() const
Get property description word. For meaning of bits see EProperty.
Bool_t IsLoaded() const
Return true if the shared library of this class is currently in the a process&#39;s memory.
Definition: TClass.cxx:5557
Int_t GetDelta()
Get offset from "this" to part of base class.
Definition: TBaseClass.cxx:75
#define DeleteBasicPointer(addr, element, name)
void Clear()
Clear string without changing its capacity.
Definition: TString.cxx:1140
std::string ResolveTypedef(const char *tname, bool resolveAll=false)
const char * GetCountClass() const
virtual void SetNewClass(TClass *cl)
EState GetState() const
Definition: TClass.h:443
Int_t fNfulldata
!number of elements
TString & Append(const char *cs)
Definition: TString.h:492
std::vector< std::vector< double > > Data
virtual void Destructor(void *p, Bool_t dtorOnly=kFALSE) const
Long_t GetThisOffset() const
Definition: TRealData.h:59
TStreamerInfoActions::TActionSequence * fReadObjectWise
! List of read action resulting from the compilation.
TDataType * GetDataType() const
Definition: TDataMember.h:74
virtual TClassStreamer * GenExplicitClassStreamer(const ::ROOT::Detail::TCollectionProxyInfo &info, TClass *cl)
Generate class streamer from static functions.
bool IsStdArray(std::string_view name)
Definition: TClassEdit.h: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:6838
Bool_t operator!=(const TDatime &d1, const TDatime &d2)
Definition: TDatime.h:103
TVirtualStreamerInfo * GetBaseStreamerInfo() const
UInt_t fCheckSum
Checksum of original class.
Definition: TStreamerInfo.h:96
Int_t GetSizeElements() const
Return total size of all persistent elements of the class use GetSize if you want to get the real siz...
const TObjArray * GetStreamerInfos() const
Definition: TClass.h:447
void Obsolete(const char *method, const char *asOfVers, const char *removedFromVers) const
Use this method to declare a method obsolete.
Definition: TObject.cxx:987
void GenerateDeclaration(FILE *fp, FILE *sfp, const TList *subClasses, Bool_t top=kTRUE)
Write the Declaration of class.
std::string GetLong64_Name(const char *original)
Replace &#39;long long&#39; and &#39;unsigned long long&#39; by &#39;Long64_t&#39; and &#39;ULong64_t&#39;.
Definition: TClassEdit.cxx:817
static void AddInclude(FILE *fp, const char *header, Bool_t system, char *inclist)
Add an include statement, if it has not already been added.
virtual void ls(Option_t *option="") const
The ls function lists the contents of a class on stdout.
Definition: TObject.cxx:537
virtual void Update(const TClass *oldClass, TClass *newClass)
function called by the TClass constructor when replacing an emulated class by the real class ...
T GetTypedValueSTLP(TVirtualCollectionProxy *cont, Int_t i, Int_t j, Int_t k, Int_t eoffset) const
Return value of element i in object number j in a TClonesArray and eventually element k in a sub-arra...
static T GetTypedValueAux(Int_t type, void *ladd, int k, Int_t len)
Get the value from inside a collection.
virtual void SetStreamer(TMemberStreamer *streamer)
set pointer to Streamer function for this element
Int_t GetMaxIndex(Int_t dim) const
Return maximum index for array dimension "dim".
A doubly linked list.
Definition: TList.h:47
void InsertArtificialElements(std::vector< const ROOT::TSchemaRule *> &rules)
Insert new members as expressed in the array of TSchemaRule(s).
Int_t GetType(Int_t id) const
static void R__WriteDestructorBody(FILE *file, TIter &next)
TClass * GetBaseClass(const char *classname)
Return pointer to the base class "classname".
Definition: TClass.cxx:2583
Int_t GetType() const
Definition: TDataType.h:70
virtual void Update(const TClass *oldClass, TClass *newClass)
function called by the TClass constructor when replacing an emulated class by the real class ...
void BuildRealData(void *pointer=0, Bool_t isTransient=kFALSE)
Build a full list of persistent data members.
Definition: TClass.cxx:1951
TClass * fClass
!pointer to class
void SetErrorMessage(const char *msg)
Int_t GetLast() const
Return index of last object in array.
Definition: TObjArray.cxx:528
static void R__TObjArray_InsertAt(TObjArray *arr, TObject *obj, Int_t at)
void ResetClassVersion(TClass *, const char *, Short_t)
Global function to update the version number.
TObjArray * fElements
Array of TStreamerElements.
virtual const char * GetInclude() const
UInt_t GenerateIncludes(FILE *fp, char *inclist, const TList *extrainfos)
Add to the header file, the #include need for this class.
virtual TObject * FindObject(const char *name) const
Must be redefined in derived classes.
Definition: TObject.cxx:380
virtual void AddAtAndExpand(TObject *obj, Int_t idx)
Add object at position idx.
Definition: TObjArray.cxx:222
TClass * GetClass() const
TRandom2 r(17)
TVirtualStreamerInfo * FindStreamerInfo(TObjArray *arr, UInt_t checksum) const
Find the TVirtualStreamerInfo in the StreamerInfos corresponding to checksum.
Definition: TClass.cxx:6625
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...
UInt_t GetCheckSum() const
Int_t GetSize() const
Definition: TArray.h:49
Basic data type descriptor (datatype information is obtained from CINT).
Definition: TDataType.h:46
void SetCountClass(const char *clname)
void CallShowMembers(const void *obj, TMemberInspector &insp, Bool_t isTransient) const
Emulated a call ShowMembers() on the obj of this class type, passing insp and parent.
virtual TObject * RemoveAt(Int_t idx)
Remove object at index idx.
Definition: TObjArray.cxx:630
Int_t fOnFileClassVersion
!Class version identifier as stored on file.
Definition: TStreamerInfo.h:98
virtual Bool_t HasPointers() const =0
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition: TObject.cxx:488
TDataMember * GetDataMember() const
Definition: TRealData.h:57
void Destructor(void *obj, Bool_t dtorOnly=kFALSE)
Explicitly call destructor for object.
Definition: TClass.cxx:5071
void IgnoreTObjectStreamer(Bool_t ignore=kTRUE)
When the class kIgnoreTObjectStreamer bit is set, the automatically generated Streamer will not call ...
Definition: TClass.cxx:4577
const TMatches FindRules(const TString &source) const
Return all the rules that are about the given &#39;source&#39; class.
TMemberStreamer * GetStreamer() const
Return the associate streamer object.
Definition: TRealData.cxx:115
Int_t GetMaxIndex(Int_t i) const
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition: TString.cxx: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
Int_t GetDataMemberOffset(TDataMember *dm, TMemberStreamer *&streamer) const
Compute data member offset.
Int_t GetEntriesFast() const
Definition: TObjArray.h:66
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:925
Ssiz_t Length() const
Definition: TString.h:390
Int_t Size() const
Return size of object of this class.
Definition: TClass.cxx:5356
const TObjArray * GetTarget() const
Get the target data members of this rule (i.e. the in memory data member).
TSubString Strip(EStripType s=kTrailing, char c=' ') const
Return a substring of self stripped at beginning and/or end.
Definition: TString.cxx:1070
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
static void R__WriteConstructorBody(FILE *file, TIter &next)
Int_t GetArrayDim() const
Return number of array dimensions.
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:81
virtual void SetByteCount(UInt_t cntpos, Bool_t packInVersion=kFALSE)=0
long double LongDouble_t
Definition: RtypesCore.h:57
ROOT::ESTLType GetCollectionType() const
Return the &#39;type&#39; of the STL the TClass is representing.
Definition: TClass.cxx:2811
static TVirtualCollectionProxy * GenEmulatedProxy(const char *class_name, Bool_t silent)
Generate emulated collection proxy for a given class.
Long_t GetOffset() const
Get offset from "this".
Long_t Property() const
Set TObject::fBits and fStreamerType to cache information about the class.
Definition: TClass.cxx:5683
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
virtual void Init(TVirtualStreamerInfo *obj=0)
Initliaze the element.
Bool_t MatchLegacyCheckSum(UInt_t checksum) const
Return true if the checksum passed as argument is one of the checksum value produced by the older che...
Definition: TClass.cxx:6062
Each class (see TClass) has a linked list of its base class(es).
Definition: TBaseClass.h:35
#define Printf
Definition: TGeoToOCC.h:18
TCompInfo * fComp
![fNslots with less than fElements->GetEntries()*1.5 used] Compiled info
TStreamerInfoActions::TActionSequence * fWriteMemberWise
! List of write action resulting from the compilation for use in member wise streaming.
Bool_t fIsBuilt
true if the StreamerInfo has been optimized
#define R__LOCKGUARD2(mutex)
PyObject * fType
TStreamerElement * fElem
Not Owned.
Definition: TStreamerInfo.h:59
T GetTypedValueClones(TClonesArray *clones, Int_t i, Int_t j, Int_t k, Int_t eoffset) const
virtual void Destructor(void *p, Bool_t dtorOnly=kFALSE)=0
const char * GetTrueTypeName() const
Get full type description of data member, e,g.: "class TDirectory*".
static UInt_t GenerateIncludeForTemplate(FILE *fp, const char *clname, char *inclist, Bool_t forward, const TList *extrainfos)
Add to the header file, the #include needed for the argument of this template.
TString & Remove(Ssiz_t pos)
Definition: TString.h: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 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:2125
Version_t GetClassVersion() const
Definition: TClass.h:382
void Build()
Build the I/O data structure for the current class version.
TObject * UncheckedAt(Int_t i) const
Definition: TObjArray.h:91
#define ClassImp(name)
Definition: Rtypes.h:279
double f(double x)
Int_t GetSize() const
Return total size of all persistent elements of the class (with offsets).
double Double_t
Definition: RtypesCore.h:55
virtual TObjArray * GetElements() const =0
Int_t fNslots
!total numbrer of slots in fComp.
TStreamerInfoActions::TActionSequence * fReadMemberWiseVecPtr
! List of read action resulting from the compilation for use in member wise streaming.
virtual Bool_t IsaPointer() const
TStreamerInfoActions::TActionSequence * fWriteObjectWise
! List of write action resulting from the compilation.
void RemoveStreamerInfo(Int_t slot)
Remove and delete the StreamerInfo in the given slot.
Definition: TClass.cxx:6862
Long_t GetDataMemberOffset(const char *membername) const
return offset for member name.
Definition: TClass.cxx:3261
virtual const char * GetFullName() const
Return element name including dimensions, if any Note that this function stores the name into a stati...
int type
Definition: TGX11.cxx:120
unsigned long long ULong64_t
Definition: RtypesCore.h:70
virtual Int_t GetSize() const
Returns size of this element in bytes.
void SetNewBaseClass(TClass *cl)
TList * GetListOfRealData() const
Definition: TClass.h:405
Bool_t HasDataMemberInfo() const
Definition: TClass.h:371
const char * GetParent() const
unsigned long ULong_t
Definition: RtypesCore.h:51
virtual Bool_t HasCounter() const
virtual Bool_t IsBase() const
Return kTRUE if the element represent a base class.
EDataType
Definition: TDataType.h:30
virtual void SetType(Int_t dtype)
Int_t fNVirtualInfoLoc
! Number of virtual info location to update.
virtual void * At(UInt_t idx)=0
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition: TString.h:567
const char * AsString() const
Return the date & time as a string (ctime() format).
Definition: TDatime.cxx:101
#define R__LOCKGUARD(mutex)
void InspectMember(const T &obj, const char *name, Bool_t isTransient)
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition: TClass.cxx:2893
void Compile()
loop on the TStreamerElement list regroup members with same type Store predigested information into l...
Bool_t IsPersistent() const
Definition: TDataMember.h:89
void TagFile(TFile *fFile)
Mark the classindex of the current file as using this TStreamerInfo.
virtual TObject * Clone(const char *newname="") const
Make a clone of an object using the Streamer facility.
Definition: TNamed.cxx:65
const TList * GetStreamerInfoCache()
Returns the cached list of StreamerInfos used in this file.
Definition: TFile.cxx:1304
Mother of all ROOT objects.
Definition: TObject.h:37
TObjArray * GetElements() const
void ls(Option_t *option="") const
List the TStreamerElement list and also the precomputed tables if option contains the string "incOrig...
virtual void Inspect(TClass *cl, const char *parent, const char *name, const void *addr)
Int_t GetNewType() const
Int_t IsSTLContainer()
The return type is defined in TDictionary (kVector, kList, etc.)
virtual UInt_t Size() const =0
TClassRef is used to implement a permanent reference to a TClass object.
Definition: TClassRef.h:33
char Char_t
Definition: RtypesCore.h:29
Int_t GetClassVersion() const
static TString UpdateAssociativeToVector(const char *name)
If we have a map, multimap, set or multiset, plus unordered partners, and the key is a class...
virtual const char * GetTitle() const
Returns title of object.
Definition: TObject.cxx:460
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition: TClass.cxx:5583
Int_t GetOnFileClassVersion() const
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.
virtual ~TStreamerInfo()
TStreamerInfo dtor.
const char * GetTypeName() const
Int_t GetNewType(Int_t id) const
virtual void ClassEnd(const TClass *)=0
Definition: file.py:1
const char * GetArrayIndex() const
If the data member is pointer and has a valid array size in its comments GetArrayIndex returns a stri...
TClass * GetNewClass() const
Int_t Size() const
Get size of basic typedef&#39;ed type.
Definition: TDataType.cxx:366
Bool_t IsVersioned() const
Definition: TClass.h:463
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.
static int fgCount
Definition: RStl.cxx:43
#define snprintf
Definition: civetweb.c:822
Int_t GetEntries() const
Return the number of objects in array (i.e.
Definition: TObjArray.cxx:494
bool IsUniquePtr(std::string_view name)
Definition: TClassEdit.h:179
R__EXTERN Int_t gDebug
Definition: Rtypes.h:128
void PrintValueSTL(const char *name, TVirtualCollectionProxy *cont, Int_t i, Int_t eoffset, Int_t lenmax=1000) const
Print value of element i in a TClonesArray.
void * NewArray(Long_t nElements, void *ary=0)
An array of emulated objects is created at address ary, if ary is null, we allocate memory for the ar...
void Add(TObject *obj)
Definition: TObjArray.h:75
const Int_t kMaxLen
TCompInfo ** fCompOpt
![fNdata]
#define gDirectory
Definition: TDirectory.h:221
double result[121]
TDataMember * GetDataMember(const char *datamember) const
Return pointer to datamember object with name "datamember".
Definition: TClass.cxx:3233
void ResetBit(UInt_t f)
Definition: TObject.h:156
unsigned char UChar_t
Definition: RtypesCore.h:34
const ROOT::Detail::TSchemaRuleSet * GetSchemaRules() const
Return the set of the schema rules if any.
Definition: TClass.cxx:1852
UInt_t GetCheckSum(ECheckSum code=kCurrentCheckSum) const
Call GetCheckSum with validity check.
Definition: TClass.cxx:6073
virtual TClass * GetClassPointer() const
Returns a pointer to the TClass of this element.
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition: TObject.cxx:953
const Bool_t kIterBackward
Definition: TCollection.h:44
virtual void Compress()
Remove empty slots from array.
Definition: TObjArray.cxx:309
virtual const char * GetName() const
Returns name of object.
Definition: TObject.cxx:416
virtual Int_t GetSize() const
Definition: TCollection.h:95
Abstract Interface class describing Streamer information for one class.
virtual const char * GetName() const
Returns name of object.
Definition: TRealData.h:56
Int_t GetNumber() const
TVirtualStreamerInfo * FindStreamerInfoAbstractEmulated(UInt_t checksum) const
For the case where the requestor class is emulated and this class is abstract, returns a pointer to t...
Definition: TClass.cxx:4511
const Bool_t kTRUE
Definition: Rtypes.h:91
TClass * GetClass() const
Definition: TDataMember.h:73
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
Definition: TNamed.cxx:155
Int_t GetOffset() const
Bool_t IsaPointer() const
Return true if data member is a pointer.
bool GetStdArrayProperties(const char *typeName, std::string &typeNameBuf, std::array< int, 5 > &maxIndices, int &ndim)
static UInt_t GenerateClassPrefix(FILE *fp, const char *clname, Bool_t top, TString &protoname, UInt_t *numberOfClasses, Int_t implementEmptyClass=kFALSE, Bool_t needGenericTemplate=kFALSE)
Write the start of the class (forward) declaration.
Int_t GetType() const
void CopyCollectionProxy(const TVirtualCollectionProxy &)
Copy the argument.
Definition: TClass.cxx:2398
void SetReadRawFunc(ROOT::TSchemaRule::ReadRawFuncPtr_t val)
Bool_t IsObject() const
Definition: TRealData.h:60
TRealData * GetRealData(const char *name) const
Return pointer to TRealData element with name "name".
Definition: TClass.cxx:3287
char name[80]
Definition: TGX11.cxx:109
const char * cnt
Definition: TXMLSetup.cxx:75
TObject * Clone(const char *newname="") const
Make a clone of an object using the Streamer facility.
Bool_t CompareContent(TClass *cl, TVirtualStreamerInfo *info, Bool_t warn, Bool_t complete, TFile *file)
Return True if the current StreamerInfo in cl or info is equivalent to this TStreamerInfo.
std::atomic< ULong_t > fLiveCount
! Number of outstanding pointer to this StreamerInfo.
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition: TObject.cxx:911
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.
virtual const char * GetTitle() const
Returns title of object.
Definition: TNamed.h:52
This class stores the date and time with a precision of one second in an unsigned 32 bit word (950130...
Definition: TDatime.h:39
TClass * GetClass() const
static void R__TObjArray_InsertAfter(TObjArray *arr, TObject *newobj, TObject *oldobj)
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition: TClass.cxx:4714
const char * Data() const
Definition: TString.h:349
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...