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