ROOT  6.06/08
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;
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();
273  fIsBuilt = kTRUE;
274  return;
275  }
276 
277  TStreamerElement::Class()->IgnoreTObjectStreamer();
278 
280 
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());
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.
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 
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.
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.
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) {
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 {
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)].",
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
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 
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()
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  Int_t sp = 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  }
1919  }
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  }
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 % sp) != 0) {
2320  offset = offset - (offset % sp) + sp;
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 {
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 
2967 ////////////////////////////////////////////////////////////////////////////////
2968 /// Recursively mark streamer infos for writing to a file.
2969 ///
2970 /// Will force this TStreamerInfo to the file and also
2971 /// all the dependencies.
2972 /// If argument force > 0 the loop on class dependencies is forced.
2973 /// This function is called when streaming a class that contains
2974 /// a null pointer. In this case, the TStreamerInfo for the class
2975 /// with the null pointer must be written to the file and also all
2976 /// the TStreamerInfo of all the classes referenced by the class.
2977 /// We must be given a file to write to.
2978 
2980 {
2981  if (!file) {
2982  return;
2983  }
2984  // Get the given file's list of streamer infos marked for writing.
2985  TArrayC* cindex = file->GetClassIndex();
2986  //the test below testing fArray[fNumber]>1 is to avoid a recursivity
2987  //problem in some cases like:
2988  // class aProblemChild: public TNamed {
2989  // aProblemChild *canBeNull;
2990  // };
2991  if ( // -- Done if already marked, and we are not forcing, or forcing is blocked.
2992  (cindex->fArray[fNumber] && !force) || // Streamer info is already marked, and not forcing, or
2993  (cindex->fArray[fNumber] > 1) // == 2 means ignore forcing to prevent infinite recursion.
2994  ) {
2995  return;
2996  }
2997  // We do not want to write streamer info to the file
2998  // for std::string.
2999  static TClassRef string_classref("string");
3000  if (fClass == string_classref) { // We are std::string.
3001  return;
3002  }
3003  // We do not want to write streamer info to the file
3004  // for STL containers.
3005  if (fClass==0) {
3006  // Build or BuildCheck has not been called yet.
3007  // Let's use another means of checking.
3008  if (fElements && fElements->GetEntries()==1 && strcmp("This",fElements->UncheckedAt(0)->GetName())==0) {
3009  // We are an STL collection.
3010  return;
3011  }
3012  } else if (fClass->GetCollectionProxy()) { // We are an STL collection.
3013  return;
3014  }
3015  // Mark ourselves for output, and block
3016  // forcing to prevent infinite recursion.
3017  cindex->fArray[fNumber] = 2;
3018  // Signal the file that the marked streamer info list has changed.
3019  cindex->fArray[0] = 1;
3020  // Recursively mark the streamer infos for
3021  // all of our elements.
3022  TIter next(fElements);
3023  TStreamerElement* element = (TStreamerElement*) next();
3024  for (; element; element = (TStreamerElement*) next()) {
3025  if (element->IsTransient()) continue;
3026  TClass* cl = element->GetClassPointer();
3027  if (cl) {
3028  TVirtualStreamerInfo* si = 0;
3029  if (cl->Property() & kIsAbstract) {
3030  // If the class of the element is abstract, register the
3031  // TStreamerInfo only if it has already been built.
3032  // Otherwise call cl->GetStreamerInfo() would generate an
3033  // incorrect StreamerInfo.
3034  si = cl->GetCurrentStreamerInfo();
3035  } else {
3036  si = cl->GetStreamerInfo();
3037  }
3038  if (si) {
3039  si->ForceWriteInfo(file, force);
3040  }
3041  }
3042  }
3043 }
3044 
3045 ////////////////////////////////////////////////////////////////////////////////
3046 /// Assuming that obj points to (the part of) an object that is of the
3047 /// type described by this streamerInfo, return the actual type of the
3048 /// object (i.e. the type described by this streamerInfo is a base class
3049 /// of the actual type of the object.
3050 /// This routine should only be called if the class decribed by this
3051 /// StreamerInfo is 'emulated'.
3052 
3053 TClass *TStreamerInfo::GetActualClass(const void *obj) const
3054 {
3055  R__ASSERT(!fClass->IsLoaded());
3056 
3057  if (fNVirtualInfoLoc != 0) {
3058  TStreamerInfo *allocator = *(TStreamerInfo**)( (const char*)obj + fVirtualInfoLoc[0] );
3059  if (allocator) return allocator->GetClass();
3060  }
3061  return (TClass*)fClass;
3062 }
3063 
3064 ////////////////////////////////////////////////////////////////////////////////
3065 /// Return true if the checksum passed as argument is one of the checksum
3066 /// value produced by the older checksum calulcation algorithm.
3067 
3069 {
3070  for(UInt_t i = 1; i < TClass::kLatestCheckSum; ++i) {
3071  if ( checksum == GetCheckSum( (TClass::ECheckSum) i) ) return kTRUE;
3072  }
3073  return kFALSE;
3074 }
3075 
3076 ////////////////////////////////////////////////////////////////////////////////
3077 /// Recalculate the checksum of this TStreamerInfo based on its code.
3078 ///
3079 /// The class ckecksum is used by the automatic schema evolution algorithm
3080 /// to uniquely identify a class version.
3081 /// The check sum is built from the names/types of base classes and
3082 /// data members.
3083 /// The valid range of code is determined by ECheckSum.
3084 /// - kNoEnum: data members of type enum are not counted in the checksum
3085 /// - kNoRange: return the checksum of data members and base classes, not including the ranges and array size found in comments.
3086 /// - kWithTypeDef: use the sugared type name in the calculation.
3087 ///
3088 /// This is needed for backward compatibility.
3089 /// ### WARNING
3090 /// This function must be kept in sync with TClass::GetCheckSum.
3091 /// They are both used to handle backward compatibility and should both return the same values.
3092 /// TStreamerInfo uses the information in TStreamerElement while TClass uses the information
3093 /// from TClass::GetListOfBases and TClass::GetListOfDataMembers.
3094 /// Original algorithm from Victor Perevovchikov (perev@bnl.gov).
3095 
3097 {
3098  // kCurrentCheckSum (0) should be kept for backward compatibility, to be
3099  // able to use the inequality checks, we need to set the code to the largest
3100  // value.
3102 
3103  UInt_t id = 0;
3104 
3105  int il;
3106  TString name = GetName();
3107  TString type;
3108  il = name.Length();
3109  for (int i=0; i<il; i++) id = id*3+name[i];
3110 
3111  TIter next(GetElements());
3112  TStreamerElement *el;
3113  while ( (el=(TStreamerElement*)next()) && !fClass->GetCollectionProxy()) { // loop over bases if not a proxied collection
3114  if (el->IsBase()) {
3115  name = el->GetName();
3116  il = name.Length();
3117  for (int i=0; i<il; i++) id = id*3+name[i];
3118  if (code > TClass::kNoBaseCheckSum && el->IsA() == TStreamerBase::Class()) {
3119  TStreamerBase *base = (TStreamerBase*)el;
3120  id = id*3 + base->GetBaseCheckSum();
3121  }
3122  }
3123  } /* End of Base Loop */
3124 
3125  next.Reset();
3126  while ( (el=(TStreamerElement*)next()) ) {
3127  if (el->IsBase()) continue;
3128 
3129  // humm can we tell if a TStreamerElement is an enum?
3130  // Maybe something like:
3131  Bool_t isenum = kFALSE;
3132  if ( el->GetType()==3 && gROOT->GetType(el->GetTypeName())==0) {
3133  // If the type is not an enum but a typedef to int then
3134  // el->GetTypeName() should be return 'int'
3135  isenum = kTRUE;
3136  }
3137  if ( (code > TClass::kNoEnum) && isenum) id = id*3 + 1;
3138 
3139  name = el->GetName(); il = name.Length();
3140 
3141  int i;
3142  for (i=0; i<il; i++) id = id*3+name[i];
3143 
3144  if (code == TClass::kReflex || code == TClass::kReflexNoComment) {
3145  // With TClass::kReflexV5 we do not want the Long64 in the name
3146  // nor any typedef.
3148 
3149  } else if (code <= TClass::kWithTypeDef) {
3150  // humm ... In the streamerInfo we only have the desugared/normalized
3151  // names, so we are unable to calculate the name with typedefs ...
3152  // except for the case of the ROOT typedef (Int_t, etc.) which are
3153  // kept by TClassEdit::ResolveTypedef(typeName) but not by TCling's
3154  // normalization ...
3155  //
3156  type = el->GetTypeName();
3157  } else {
3159  }
3160  if (TClassEdit::IsSTLCont(type)) {
3162  }
3163  if (code == TClass::kReflex || code == TClass::kReflexNoComment) {
3164  type.ReplaceAll("ULong64_t","unsigned long long");
3165  type.ReplaceAll("Long64_t","long long");
3166  type.ReplaceAll("signed char","char");
3167  type.ReplaceAll("<signed char","<char");
3168  type.ReplaceAll(",signed char",",char");
3169  if (type=="signed char") type = "char";
3170  }
3171 
3172  il = type.Length();
3173  for (i=0; i<il; i++) id = id*3+type[i];
3174 
3175  int dim = el->GetArrayDim();
3176  if (dim) {
3177  for (i=0;i<dim;i++) id = id*3+el->GetMaxIndex(i);
3178  }
3179 
3180 
3181  if (code > TClass::kNoRange) {
3182  const char *left;
3183  if (code > TClass::kNoRangeCheck)
3185  else
3186  left = strstr(el->GetTitle(),"[");
3187  if (left) {
3188  const char *right = strstr(left,"]");
3189  if (right) {
3190  ++left;
3191  while (left != right) {
3192  id = id*3 + *left;
3193  ++left;
3194  }
3195  }
3196  }
3197  }
3198  }
3199  return id;
3200 }
3201 
3202 ////////////////////////////////////////////////////////////////////////////////
3203 
3204 static void R__WriteConstructorBody(FILE *file, TIter &next)
3205 {
3206  TStreamerElement *element = 0;
3207  next.Reset();
3208  while ((element = (TStreamerElement*)next())) {
3213  if(element->GetArrayLength() <= 1) {
3214  fprintf(file," %s = 0;\n",element->GetName());
3215  } else {
3216  fprintf(file," memset(%s,0,%d);\n",element->GetName(),element->GetSize());
3217  }
3218  }
3219  if (TVirtualStreamerInfo::kOffsetP <= element->GetType() && element->GetType() < TVirtualStreamerInfo::kObject ) {
3220  fprintf(file," %s = 0;\n",element->GetName());
3221  }
3222  }
3223 }
3224 
3225 ////////////////////////////////////////////////////////////////////////////////
3226 /// Write down the body of the 'move' constructor.
3227 
3228 static void R__WriteMoveConstructorBody(FILE *file, const TString &protoname, TIter &next)
3229 {
3230  TStreamerElement *element = 0;
3231  next.Reset();
3232  Bool_t atstart = kTRUE;
3233  while ((element = (TStreamerElement*)next())) {
3234  if (element->IsBase()) {
3235  if (atstart) { fprintf(file," : "); atstart = kFALSE; }
3236  else fprintf(file," , ");
3237  fprintf(file, "%s(const_cast<%s &>( rhs ))\n", element->GetName(),protoname.Data());
3238  } else {
3239  if (element->GetArrayLength() <= 1) {
3240  if (atstart) { fprintf(file," : "); atstart = kFALSE; }
3241  else fprintf(file," , ");
3242  fprintf(file, "%s(const_cast<%s &>( rhs ).%s)\n",element->GetName(),protoname.Data(),element->GetName());
3243  }
3244  }
3245  }
3246  fprintf(file,"{\n");
3247  fprintf(file," // This is NOT a copy constructor. This is actually a move constructor (for stl container's sake).\n");
3248  fprintf(file," // Use at your own risk!\n");
3249  fprintf(file," (void)rhs; // avoid warning about unused parameter\n");
3250  next.Reset();
3251  Bool_t defMod = kFALSE;
3252  while ((element = (TStreamerElement*)next())) {
3255  || element->GetType() == TVirtualStreamerInfo::kAnyPnoVT)
3256  {
3257  if (!defMod) { fprintf(file," %s &modrhs = const_cast<%s &>( rhs );\n",protoname.Data(),protoname.Data()); defMod = kTRUE; };
3258  const char *ename = element->GetName();
3259  const char *colon2 = strstr(ename,"::");
3260  if (colon2) ename = colon2+2;
3261  if(element->GetArrayLength() <= 1) {
3262  fprintf(file," modrhs.%s = 0;\n",ename);
3263  } else {
3264  fprintf(file," memset(modrhs.%s,0,%d);\n",ename,element->GetSize());
3265  }
3266  } else {
3267  const char *ename = element->GetName();
3268  if (element->GetType() == kCharStar) {
3269  if (!defMod) {
3270  fprintf(file," %s &modrhs = const_cast<%s &>( rhs );\n",protoname.Data(),protoname.Data()); defMod = kTRUE;
3271  };
3272  fprintf(file," modrhs.%s = 0;\n",ename);
3273  } else if (TVirtualStreamerInfo::kOffsetP <= element->GetType() && element->GetType() < TVirtualStreamerInfo::kObject ) {
3274  if (!defMod) {
3275  fprintf(file," %s &modrhs = const_cast<%s &>( rhs );\n",protoname.Data(),protoname.Data()); defMod = kTRUE;
3276  };
3277  fprintf(file," modrhs.%s = 0;\n",ename);
3278  } else if (element->GetArrayLength() > 1) {
3279  // FIXME: Need to add support for variable length array.
3280  if (element->GetArrayDim() == 1) {
3281  fprintf(file," for (Int_t i=0;i<%d;i++) %s[i] = rhs.%s[i];\n",element->GetArrayLength(),ename,ename);
3282  } else if (element->GetArrayDim() >= 2) {
3283  fprintf(file," for (Int_t i=0;i<%d;i++) (&(%s",element->GetArrayLength(),ename);
3284  for (Int_t d = 0; d < element->GetArrayDim(); ++d) {
3285  fprintf(file,"[0]");
3286  }
3287  fprintf(file,"))[i] = (&(rhs.%s",ename);
3288  for (Int_t d = 0; d < element->GetArrayDim(); ++d) {
3289  fprintf(file,"[0]");
3290  }
3291  fprintf(file,"))[i];\n");
3292  }
3293  } else if (element->GetType() == TVirtualStreamerInfo::kSTLp) {
3294  if (!defMod) { fprintf(file," %s &modrhs = const_cast<%s &>( rhs );\n",protoname.Data(),protoname.Data()); defMod = kTRUE; };
3295  fprintf(file," modrhs.%s = 0;\n",ename);
3296  } else if (element->GetType() == TVirtualStreamerInfo::kSTL) {
3297  if (!defMod) {
3298  fprintf(file," %s &modrhs = const_cast<%s &>( rhs );\n",protoname.Data(),protoname.Data()); defMod = kTRUE;
3299  }
3300  TClass *cle = element->GetClassPointer();
3301  TVirtualCollectionProxy *proxy = cle ? element->GetClassPointer()->GetCollectionProxy() : 0;
3302  std::string method_name = "clear";
3303  if (!element->TestBit(TStreamerElement::kDoNotDelete) && proxy && (((TStreamerSTL*)element)->GetSTLtype() == ROOT::kSTLbitset)) {
3304  method_name = "reset";
3305  }
3306  if (element->IsBase()) {
3307  fprintf(file," modrhs.%s();\n", method_name.c_str());
3308  } else {
3309  fprintf(file," modrhs.%s.%s();\n",ename, method_name.c_str());
3310  }
3311  }
3312  }
3313  }
3314 }
3315 
3316 ////////////////////////////////////////////////////////////////////////////////
3317 
3318 static void R__WriteDestructorBody(FILE *file, TIter &next)
3319 {
3320  TStreamerElement *element = 0;
3321  next.Reset();
3322  while ((element = (TStreamerElement*)next())) {
3325  || element->GetType() == TVirtualStreamerInfo::kAnyPnoVT)
3326  {
3327  const char *ename = element->GetName();
3328  const char *colon2 = strstr(ename,"::");
3329  if (colon2) ename = colon2+2;
3330  if (element->TestBit(TStreamerElement::kDoNotDelete)) {
3331  if(element->GetArrayLength() <= 1) {
3332  fprintf(file," %s = 0;\n",ename);
3333  } else {
3334  fprintf(file," memset(%s,0,%d);\n",ename,element->GetSize());
3335  }
3336  } else {
3337  if(element->GetArrayLength() <= 1) {
3338  fprintf(file," delete %s; %s = 0;\n",ename,ename);
3339  } else {
3340  fprintf(file," for (Int_t i=0;i<%d;i++) delete %s[i]; memset(%s,0,%d);\n",element->GetArrayLength(),ename,ename,element->GetSize());
3341  }
3342  }
3343  }
3344  if (element->GetType() == TVirtualStreamerInfo::kCharStar) {
3345  const char *ename = element->GetName();
3346  if (element->TestBit(TStreamerElement::kDoNotDelete)) {
3347  fprintf(file," %s = 0;\n",ename);
3348  } else {
3349  fprintf(file," delete [] %s; %s = 0;\n",ename,ename);
3350  }
3351  }
3352  if (TVirtualStreamerInfo::kOffsetP <= element->GetType() && element->GetType() < TVirtualStreamerInfo::kObject ) {
3353  const char *ename = element->GetName();
3354  if (element->TestBit(TStreamerElement::kDoNotDelete)) {
3355  fprintf(file," %s = 0;\n",ename);
3356  } else if (element->HasCounter()) {
3357  fprintf(file," delete %s; %s = 0;\n",ename,ename);
3358  } else {
3359  fprintf(file," delete [] %s; %s = 0;\n",ename,ename);
3360  }
3361  }
3362  if (element->GetType() == TVirtualStreamerInfo::kSTL || element->GetType() == TVirtualStreamerInfo::kSTLp) {
3363  const char *ename = element->GetName();
3364  const char *prefix = "";
3365  if ( element->GetType() == TVirtualStreamerInfo::kSTLp ) {
3366  prefix = "*";
3367  } else if ( element->IsBase() ) {
3368  ename = "this";
3369  }
3370  TClass *cle = element->GetClassPointer();
3371  TVirtualCollectionProxy *proxy = cle ? element->GetClassPointer()->GetCollectionProxy() : 0;
3372  if (!element->TestBit(TStreamerElement::kDoNotDelete) && proxy) {
3373  Int_t stltype = ((TStreamerSTL*)element)->GetSTLtype();
3374 
3375  if (proxy->HasPointers()) {
3376  fprintf(file," std::for_each( (%s %s).rbegin(), (%s %s).rend(), DeleteObjectFunctor() );\n",prefix,ename,prefix,ename);
3377  //fprintf(file," %s::iterator iter;\n");
3378  //fprintf(file," %s::iterator begin = (%s %s).begin();\n");
3379  //fprintf(file," %s::iterator end (%s %s).end();\n");
3380  //fprintf(file," for( iter = begin; iter != end; ++iter) { delete *iter; }\n");
3381  } else {
3382  if (stltype == ROOT::kSTLmap || stltype == ROOT::kSTLmultimap) {
3384  std::vector<std::string> inside;
3385  int nestedLoc;
3386  TClassEdit::GetSplit(enamebasic, inside, nestedLoc, TClassEdit::kLong64);
3387  if (inside[1][inside[1].size()-1]=='*' || inside[2][inside[2].size()-1]=='*') {
3388  fprintf(file," std::for_each( (%s %s).rbegin(), (%s %s).rend(), DeleteObjectFunctor() );\n",prefix,ename,prefix,ename);
3389  }
3390  }
3391  }
3392  }
3393  if ( prefix[0] ) {
3394  fprintf(file," delete %s; %s = 0;\n",ename,ename);
3395  }
3396  }
3397  }
3398 }
3399 
3400 ////////////////////////////////////////////////////////////////////////////////
3401 /// Write the Declaration of class.
3402 
3403 void TStreamerInfo::GenerateDeclaration(FILE *fp, FILE *sfp, const TList *subClasses, Bool_t top)
3404 {
3405  if (fClassVersion == -3) {
3406  return;
3407  }
3408 
3409  Bool_t needGenericTemplate = fElements==0 || fElements->GetEntries() == 0;
3410  Bool_t isTemplate = kFALSE;
3411  const char *clname = GetName();
3412  TString template_protoname;
3413  if (strchr(clname, ':')) {
3414  // We might have a namespace in front of the classname.
3415  Int_t len = strlen(clname);
3416  const char *name = clname;
3417  UInt_t nest = 0;
3418  UInt_t pr_pos = 0;
3419  for (Int_t cur = 0; cur < len; ++cur) {
3420  switch (clname[cur]) {
3421  case '<':
3422  ++nest;
3423  pr_pos = cur;
3424  isTemplate = kTRUE;
3425  break;
3426  case '>':
3427  if (nest == 0) { cur = len; continue; } // the name is not well formed, give up.
3428  --nest;
3429  break;
3430  case ':': {
3431  if (nest == 0 && clname[cur+1] == ':') {
3432  // We have a scope
3433  isTemplate = kFALSE;
3434  name = clname + cur + 2;
3435  }
3436  break;
3437  }
3438  }
3439  }
3440  if (isTemplate) {
3441  template_protoname.Append(clname,pr_pos);
3442  }
3443  clname = name;
3444  } else {
3445  const char *where = strstr(clname, "<");
3446  isTemplate = where != 0;
3447  if (isTemplate) {
3448  template_protoname.Append(clname,where-clname);
3449  }
3450  }
3451 
3452  if (needGenericTemplate && isTemplate) {
3453  TString templateName(TMakeProject::GetHeaderName("template "+template_protoname,0));
3454  fprintf(fp, "#ifndef %s_h\n", templateName.Data());
3455  fprintf(fp, "#define %s_h\n", templateName.Data());
3456  }
3457 
3458  TString protoname;
3459  UInt_t numberOfNamespaces = TMakeProject::GenerateClassPrefix(fp, GetName(), top, protoname, 0, kFALSE, needGenericTemplate);
3460 
3461  // Generate class statement with base classes.
3462  TStreamerElement *element;
3463  TIter next(fElements);
3464  Int_t nbase = 0;
3465  while ((element = (TStreamerElement*)next())) {
3466  if (!element->IsBase()) continue;
3467  nbase++;
3468  const char *ename = element->GetName();
3469  if (nbase == 1) fprintf(fp," : public %s",ename);
3470  else fprintf(fp," , public %s",ename);
3471  }
3472  fprintf(fp," {\n");
3473 
3474  // Generate forward declaration nested classes.
3475  if (subClasses && subClasses->GetEntries()) {
3476  Bool_t needheader = true;
3477 
3478  TIter subnext(subClasses);
3479  TStreamerInfo *subinfo;
3480  Int_t len = strlen(GetName());
3481  while ((subinfo = (TStreamerInfo*)subnext())) {
3482  if (strncmp(GetName(),subinfo->GetName(),len)==0 && (subinfo->GetName()[len]==':') ) {
3483  if (subinfo->GetName()[len+1]==':' && strstr(subinfo->GetName()+len+2,":")==0) {
3484  if (needheader) {
3485  fprintf(fp,"\npublic:\n");
3486  fprintf(fp,"// Nested classes forward declaration.\n");
3487  needheader = false;
3488  }
3489  TString sub_protoname;
3490  UInt_t sub_numberOfClasses = 0;
3491  UInt_t sub_numberOfNamespaces;
3492  if (subinfo->GetClassVersion() == -3) {
3493  sub_numberOfNamespaces = TMakeProject::GenerateClassPrefix(fp, subinfo->GetName() + len+2, kFALSE, sub_protoname, &sub_numberOfClasses, 3);
3494  } else {
3495  sub_numberOfNamespaces = TMakeProject::GenerateClassPrefix(fp, subinfo->GetName() + len+2, kFALSE, sub_protoname, &sub_numberOfClasses, kFALSE);
3496  fprintf(fp, ";\n");
3497  }
3498 
3499  for (UInt_t i = 0;i < sub_numberOfClasses;++i) {
3500  fprintf(fp, "}; // end of class.\n");
3501  }
3502  if (sub_numberOfNamespaces > 0) {
3503  Error("GenerateDeclaration","Nested classes %s thought to be inside a namespace inside the class %s",subinfo->GetName(),GetName());
3504  }
3505  }
3506  }
3507  }
3508  }
3509 
3510  fprintf(fp,"\npublic:\n");
3511  fprintf(fp,"// Nested classes declaration.\n");
3512 
3513  // Generate nested classes.
3514  if (subClasses && subClasses->GetEntries()) {
3515  TIter subnext(subClasses,kIterBackward);
3516  TStreamerInfo *subinfo;
3517  Int_t len = strlen(GetName());
3518  while ((subinfo = (TStreamerInfo*)subnext())) {
3519  if (strncmp(GetName(),subinfo->GetName(),len)==0 && (subinfo->GetName()[len]==':')) {
3520  if (subinfo->GetName()[len+1]==':' && strstr(subinfo->GetName()+len+2,":")==0) {
3521  subinfo->GenerateDeclaration(fp, sfp, subClasses, kFALSE);
3522  }
3523  }
3524  }
3525  }
3526 
3527  fprintf(fp,"\npublic:\n");
3528  fprintf(fp,"// Data Members.\n");
3529 
3530  {
3531  // Generate data members.
3532  TString name(128);
3533  Int_t ltype = 12;
3534  Int_t ldata = 10;
3535  Int_t lt,ld,is;
3536  TString line;
3537  line.Resize(kMaxLen);
3538  next.Reset();
3539  while ((element = (TStreamerElement*)next())) {
3540 
3541  if (element->IsBase()) continue;
3542  const char *ename = element->GetName();
3543 
3544  name = ename;
3545  for (Int_t i=0;i < element->GetArrayDim();i++) {
3546  name += TString::Format("[%d]",element->GetMaxIndex(i));
3547  }
3548  name += ";";
3549  ld = name.Length();
3550 
3551  TString enamebasic = element->GetTypeNameBasic();
3552  if (element->IsA() == TStreamerSTL::Class()) {
3553  // If we have a map, multimap, set or multiset,
3554  // and the key is a class, we need to replace the
3555  // container by a vector since we don't have the
3556  // comparator function.
3557  Int_t stltype = ((TStreamerSTL*)element)->GetSTLtype();
3558  switch (stltype) {
3559  case ROOT::kSTLmap:
3560  case ROOT::kSTLmultimap:
3561  case ROOT::kSTLset:
3562  case ROOT::kSTLmultiset:
3565  {
3566  enamebasic = TMakeProject::UpdateAssociativeToVector(enamebasic);
3567  }
3568  default:
3569  // nothing to do.
3570  break;
3571  }
3572  }
3573 
3574  lt = enamebasic.Length();
3575 
3576  line = " ";
3577  line += enamebasic;
3578  if (lt>=ltype) ltype = lt+1;
3579 
3580  for (is = 3+lt; is < (3+ltype); ++is) line += ' ';
3581 
3582  line += name;
3583  if (element->IsaPointer() && !strchr(line,'*')) line[2+ltype] = '*';
3584 
3585  if (ld>=ldata) ldata = ld+1;
3586  for (is = 3+ltype+ld; is < (3+ltype+ldata); ++is) line += ' ';
3587 
3588  line += " //";
3589  line += element->GetTitle();
3590  fprintf(fp,"%s\n",line.Data());
3591  }
3592  }
3593  if (needGenericTemplate && isTemplate) {
3594  // Generate default functions, ClassDef and trailer.
3595  fprintf(fp,"\n %s() {\n",protoname.Data());
3596  R__WriteConstructorBody(fp,next);
3597  fprintf(fp," }\n");
3598  fprintf(fp," %s(const %s & rhs )\n",protoname.Data(),protoname.Data());
3599  R__WriteMoveConstructorBody(fp,protoname,next);
3600  fprintf(fp," }\n");
3601  fprintf(fp," virtual ~%s() {\n",protoname.Data());
3602  R__WriteDestructorBody(fp,next);
3603  fprintf(fp," }\n\n");
3604 
3605  } else {
3606  // Generate default functions, ClassDef and trailer.
3607  fprintf(fp,"\n %s();\n",protoname.Data());
3608  fprintf(fp," %s(const %s & );\n",protoname.Data(),protoname.Data());
3609  fprintf(fp," virtual ~%s();\n\n",protoname.Data());
3610 
3611  // Add the implementations to the source.cxx file.
3613  fprintf(sfp,"#ifndef %s_cxx\n",guard.Data());
3614  fprintf(sfp,"#define %s_cxx\n",guard.Data());
3615  fprintf(sfp,"%s::%s() {\n",GetName(),protoname.Data());
3616  R__WriteConstructorBody(sfp,next);
3617  fprintf(sfp,"}\n");
3618 
3619  fprintf(sfp,"%s::%s(const %s & rhs)\n",GetName(),protoname.Data(),protoname.Data());
3620  R__WriteMoveConstructorBody(sfp,protoname,next);
3621  fprintf(sfp,"}\n");
3622 
3623  fprintf(sfp,"%s::~%s() {\n",GetName(),protoname.Data());
3624  R__WriteDestructorBody(sfp,next);
3625  fprintf(sfp,"}\n");
3626  fprintf(sfp,"#endif // %s_cxx\n\n",guard.Data());
3627  }
3628 
3629  TClass *cl = gROOT->GetClass(GetName());
3630  if (fClassVersion > 1 || (cl && cl->IsTObject()) ) {
3631  // add 1 to class version in case we didn't manage reproduce the class layout to 100%.
3632  if (fClassVersion == 0) {
3633  // If the class was declared 'transient', keep it that way.
3634  fprintf(fp," ClassDef(%s,%d); // Generated by MakeProject.\n",protoname.Data(),0);
3635  } else {
3636  fprintf(fp," ClassDef(%s,%d); // Generated by MakeProject.\n",protoname.Data(),fClassVersion + 1);
3637  }
3638  }
3639  fprintf(fp,"};\n");
3640 
3641  for(UInt_t i=0;i<numberOfNamespaces;++i) {
3642  fprintf(fp,"} // namespace\n");
3643  }
3644 
3645  if (needGenericTemplate && isTemplate) {
3646  fprintf(fp,"#endif // generic template declaration\n");
3647  }
3648 }
3649 
3650 ////////////////////////////////////////////////////////////////////////////////
3651 /// Add to the header file, the \#include need for this class.
3652 
3653 UInt_t TStreamerInfo::GenerateIncludes(FILE *fp, char *inclist, const TList *extrainfos)
3654 {
3655  UInt_t ninc = 0;
3656 
3657  const char *clname = GetName();
3658  if (strchr(clname,'<')) {
3659  // This is a template, we need to check the template parameter.
3660  ninc += TMakeProject::GenerateIncludeForTemplate(fp, clname, inclist, kFALSE, extrainfos);
3661  }
3662 
3663  TString name(1024);
3664  Int_t ltype = 10;
3665  Int_t ldata = 10;
3666  Int_t lt;
3667  Int_t ld;
3668  TIter next(fElements);
3669  TStreamerElement *element;
3670  Bool_t incRiostream = kFALSE;
3671  while ((element = (TStreamerElement*)next())) {
3672  //if (element->IsA() == TStreamerBase::Class()) continue;
3673  const char *ename = element->GetName();
3674  const char *colon2 = strstr(ename,"::");
3675  if (colon2) ename = colon2+2;
3676  name = ename;
3677  for (Int_t i=0;i < element->GetArrayDim();i++) {
3678  name += TString::Format("[%d]",element->GetMaxIndex(i));
3679  }
3680  ld = name.Length();
3681  lt = strlen(element->GetTypeName());
3682  if (ltype < lt) ltype = lt;
3683  if (ldata < ld) ldata = ld;
3684 
3685  //must include Riostream.h in case of an STL container
3686  if (!incRiostream && element->InheritsFrom(TStreamerSTL::Class())) {
3687  incRiostream = kTRUE;
3688  TMakeProject::AddInclude( fp, "Riostream.h", kFALSE, inclist);
3689  }
3690 
3691  //get include file name if any
3692  const char *include = element->GetInclude();
3693  if (!include[0]) continue;
3694 
3695  Bool_t greater = (include[0]=='<');
3696  include++;
3697 
3698  if (strncmp(include,"include/",8)==0) {
3699  include += 8;
3700  }
3701  if (strncmp(include,"include\\",9)==0) {
3702  include += 9;
3703  }
3704  if (strncmp(element->GetTypeName(),"pair<",strlen("pair<"))==0) {
3705  TMakeProject::AddInclude( fp, "utility", kTRUE, inclist);
3706  } else if (strncmp(element->GetTypeName(),"auto_ptr<",strlen("auto_ptr<"))==0) {
3707  TMakeProject::AddInclude( fp, "memory", kTRUE, inclist);
3708  } else {
3709  TString incName( include, strlen(include)-1 );
3710  incName = TMakeProject::GetHeaderName(incName,extrainfos);
3711  TMakeProject::AddInclude( fp, incName.Data(), greater, inclist);
3712  }
3713 
3714  if (strchr(element->GetTypeName(),'<')) {
3715  // This is a template, we need to check the template parameter.
3716  ninc += TMakeProject::GenerateIncludeForTemplate(fp, element->GetTypeName(), inclist, kFALSE, extrainfos);
3717  }
3718  }
3719  if (inclist[0]==0) {
3720  TMakeProject::AddInclude( fp, "TNamed.h", kFALSE, inclist);
3721  }
3722  return ninc;
3723 }
3724 
3725 ////////////////////////////////////////////////////////////////////////////////
3726 /// Generate header file for the class described by this TStreamerInfo
3727 /// the function is called by TFile::MakeProject for each class in the file
3728 
3729 Int_t TStreamerInfo::GenerateHeaderFile(const char *dirname, const TList *subClasses, const TList *extrainfos)
3730 {
3731  // if (fClassVersion == -4) return 0;
3732  if ((fClass && fClass->GetCollectionType()) || TClassEdit::IsSTLCont(GetName())) return 0;
3733  if (strncmp(GetName(),"pair<",strlen("pair<"))==0) return 0;
3734  if (strncmp(GetName(),"auto_ptr<",strlen("auto_ptr<"))==0) return 0;
3735 
3736  TClass *cl = TClass::GetClass(GetName());
3737  if (cl) {
3738  if (cl->HasInterpreterInfo()) return 0; // skip known classes
3739  }
3740  Bool_t isTemplate = kFALSE;
3741  if (strchr(GetName(),':')) {
3742  UInt_t len = strlen(GetName());
3743  UInt_t nest = 0;
3744  UInt_t scope = 0;
3745  for(UInt_t i=len; i>0; --i) {
3746  switch(GetName()[i]) {
3747  case '>': ++nest; if (scope==0) { isTemplate = kTRUE; } break;
3748  case '<': --nest; break;
3749  case ':':
3750  if (nest==0 && GetName()[i-1]==':') {
3751  // We have a scope
3752  TString nsname(GetName(), i-1);
3753  cl = gROOT->GetClass(nsname);
3754  if (cl && (cl->Size()!=0 || (cl->Size()==0 && !cl->HasInterpreterInfo() /*empty 'base' class on file*/))) {
3755  // This class is actually nested.
3756  return 0;
3757  } else if (cl == 0 && extrainfos != 0) {
3758  TStreamerInfo *clinfo = (TStreamerInfo*)extrainfos->FindObject(nsname);
3759  if (clinfo && clinfo->GetClassVersion() == -5) {
3760  // This class is actually nested.
3761  return 0;
3762  }
3763  }
3764  ++scope;
3765  }
3766  break;
3767  }
3768  }
3769  }
3770  Bool_t needGenericTemplate = isTemplate && (fElements==0 || fElements->GetEntries()==0);
3771 
3772  if (gDebug) printf("generating code for class %s\n",GetName());
3773 
3774  // Open the file
3775 
3776  TString headername( TMakeProject::GetHeaderName( GetName(), extrainfos ) );
3777  TString filename;
3778  filename.Form("%s/%s.h",dirname,headername.Data());
3779 
3780  FILE *fp = fopen(filename.Data(),"w");
3781  if (!fp) {
3782  Error("MakeProject","Cannot open output file:%s\n",filename.Data());
3783  return 0;
3784  }
3785 
3786  filename.Form("%s/%sProjectHeaders.h",dirname,gSystem->BaseName(dirname));
3787  FILE *allfp = fopen(filename.Data(),"a");
3788  if (!allfp) {
3789  Error("MakeProject","Cannot open output file:%s\n",filename.Data());
3790  fclose(fp);
3791  return 0;
3792  }
3793  fprintf(allfp,"#include \"%s.h\"\n", headername.Data());
3794  fclose(allfp);
3795 
3796  char *inclist = new char[50000];
3797  inclist[0] = 0;
3798 
3799  // Generate class header.
3800  TDatime td;
3801  fprintf(fp,"//////////////////////////////////////////////////////////\n");
3802  fprintf(fp,"// This class has been generated by TFile::MakeProject\n");
3803  fprintf(fp,"// (%s by ROOT version %s)\n",td.AsString(),gROOT->GetVersion());
3804  fprintf(fp,"// from the StreamerInfo in file %s\n",gDirectory->GetFile()->GetName());
3805  fprintf(fp,"//////////////////////////////////////////////////////////\n");
3806  fprintf(fp,"\n");
3807  fprintf(fp,"\n");
3808  fprintf(fp,"#ifndef %s_h\n",headername.Data());
3809  fprintf(fp,"#define %s_h\n",headername.Data());
3810  TMakeProject::GenerateForwardDeclaration(fp, GetName(), inclist, kFALSE, needGenericTemplate, extrainfos);
3811  fprintf(fp,"\n");
3812 
3813  UInt_t ninc = 0;
3814  ninc += GenerateIncludes(fp, inclist, extrainfos);
3815  if (subClasses) {
3816  TIter subnext(subClasses);
3817  TStreamerInfo *subinfo;
3818  while ((subinfo = (TStreamerInfo*)subnext())) {
3819  ninc = subinfo->GenerateIncludes(fp, inclist, extrainfos);
3820  }
3821  }
3822  fprintf(fp,"\n");
3823 
3824  TString sourcename; sourcename.Form( "%s/%sProjectSource.cxx", dirname, gSystem->BaseName(dirname) );
3825  FILE *sfp = fopen( sourcename.Data(), "a" );
3826  if (sfp) {
3827  GenerateDeclaration(fp, sfp, subClasses);
3828  } else {
3829  Error("GenerateHeaderFile","Could not open %s for appending",sourcename.Data());
3830  }
3831  TMakeProject::GeneratePostDeclaration(fp, this, inclist);
3832 
3833  fprintf(fp,"#endif\n");
3834 
3835  delete [] inclist;
3836  fclose(fp);
3837  if (sfp) fclose(sfp);
3838  return 1;
3839 }
3840 
3841 ////////////////////////////////////////////////////////////////////////////////
3842 /// Compute data member offset.
3843 /// Return pointer to the Streamer function if one exists
3844 
3846 {
3847  TIter nextr(fClass->GetListOfRealData());
3848  char dmbracket[256];
3849  snprintf(dmbracket,255,"%s[",dm->GetName());
3850  Int_t offset = kMissing;
3851  if (!fClass->IsLoaded()) {
3852  // If the 'class' is not loaded, we do not have a TClass bootstrap and thus
3853  // the 'RealData' might not have enough information because of the lack
3854  // of proper ShowMember imlementation.
3855  if (! (dm->Property() & kIsStatic) ) {
3856  // Give an offset only to non-static members.
3857  offset = dm->GetOffset();
3858  }
3859  }
3860  TRealData *rdm;
3861  while ((rdm = (TRealData*)nextr())) {
3862  char *rdmc = (char*)rdm->GetName();
3863  //next statement required in case a class and one of its parent class
3864  //have data members with the same name
3865  if (dm->IsaPointer() && rdmc[0] == '*') rdmc++;
3866 
3867  if (rdm->GetDataMember() != dm) continue;
3868  if (strcmp(rdmc,dm->GetName()) == 0) {
3869  offset = rdm->GetThisOffset();
3870  streamer = rdm->GetStreamer();
3871  break;
3872  }
3873  if (strcmp(rdm->GetName(),dm->GetName()) == 0) {
3874  if (rdm->IsObject()) {
3875  offset = rdm->GetThisOffset();
3876  streamer = rdm->GetStreamer();
3877  break;
3878  }
3879  }
3880  if (strstr(rdm->GetName(),dmbracket)) {
3881  offset = rdm->GetThisOffset();
3882  streamer = rdm->GetStreamer();
3883  break;
3884  }
3885  }
3886  return offset;
3887 }
3888 
3889 ////////////////////////////////////////////////////////////////////////////////
3890 /// Return the offset of the data member as indicated by this StreamerInfo.
3891 
3892 Int_t TStreamerInfo::GetOffset(const char *elementName) const
3893 {
3894  if (elementName == 0) return 0;
3895 
3896  Int_t offset = 0;
3897  TStreamerElement *elem = (TStreamerElement*)fElements->FindObject(elementName);
3898  if (elem) offset = elem->GetOffset();
3899 
3900  return offset;
3901 }
3902 
3903 ////////////////////////////////////////////////////////////////////////////////
3904 /// Return total size of all persistent elements of the class (with offsets).
3905 
3907 {
3908  return fSize;
3909 }
3910 
3911 ////////////////////////////////////////////////////////////////////////////////
3912 /// Return total size of all persistent elements of the class
3913 /// use GetSize if you want to get the real size in memory.
3914 
3916 {
3917  TIter next(fElements);
3918  TStreamerElement *element;
3919  Int_t asize = 0;
3920  while ((element = (TStreamerElement*)next())) {
3921  asize += element->GetSize();
3922  }
3923  return asize;
3924 }
3925 
3926 ////////////////////////////////////////////////////////////////////////////////
3927 /// Return the StreamerElement of "datamember" inside our
3928 /// class or any of its base classes.
3929 ///
3930 /// The offset information
3931 /// contained in the StreamerElement is related to its immediately
3932 /// containing class, so we return in 'offset' the offset inside
3933 /// our class.
3934 
3935 TStreamerElement* TStreamerInfo::GetStreamerElement(const char* datamember, Int_t& offset) const
3936 {
3937  if (!fElements) {
3938  return 0;
3939  }
3940 
3941  // Look first at the data members and base classes
3942  // of our class.
3943  TStreamerElement* element = (TStreamerElement*) fElements->FindObject(datamember);
3944  if (element) {
3945  offset = element->GetOffset();
3946  return element;
3947  }
3948 
3949  // Not found, so now try the data members and base classes
3950  // of the base classes of our class.
3951  if (fClass->HasDataMemberInfo()) {
3952  // Our class has a dictionary loaded, use it to search the base classes.
3953  TStreamerElement* base_element = 0;
3954  TBaseClass* base = 0;
3955  TClass* base_cl = 0;
3956  Int_t base_offset = 0;
3957  Int_t local_offset = 0;
3958  TIter nextb(fClass->GetListOfBases());
3959  // Iterate on list of base classes.
3960  while ((base = (TBaseClass*) nextb())) {
3961  base_cl = TClass::GetClass(base->GetName());
3962  base_element = (TStreamerElement*) fElements->FindObject(base->GetName());
3963  if (!base_cl || !base_element) {
3964  continue;
3965  }
3966  base_offset = base_element->GetOffset();
3967  element = ((TStreamerInfo*)base_cl->GetStreamerInfo())->GetStreamerElement(datamember, local_offset);
3968  if (element) {
3969  offset = base_offset + local_offset;
3970  return element;
3971  }
3972  }
3973  } else {
3974  // Our class's dictionary is not loaded. Search through the base class streamer elements.
3975  TIter next(fElements);
3976  TStreamerElement* curelem = 0;
3977  while ((curelem = (TStreamerElement*) next())) {
3978  if (curelem->InheritsFrom(TStreamerBase::Class())) {
3979  TClass* baseClass = curelem->GetClassPointer();
3980  if (!baseClass) {
3981  continue;
3982  }
3983  Int_t base_offset = curelem->GetOffset();
3984  Int_t local_offset = 0;
3985  TStreamerInfo *baseInfo;
3986  if (baseClass->Property() & kIsAbstract) {
3987  baseInfo = (TStreamerInfo*)baseClass->GetStreamerInfoAbstractEmulated();
3988  } else {
3989  baseInfo = (TStreamerInfo*)baseClass->GetStreamerInfo();
3990  }
3991  if (baseInfo) element = baseInfo->GetStreamerElement(datamember, local_offset);
3992  if (element) {
3993  offset = base_offset + local_offset;
3994  return element;
3995  }
3996  }
3997  }
3998  }
3999  return 0;
4000 }
4001 
4002 ////////////////////////////////////////////////////////////////////////////////
4003 /// <b>Obsolete</b>: this routine is obsolete and should not longer be used.
4004 ///
4005 /// TStreamerInfo holds two types of data structures
4006 /// - TObjArray* fElements; containing the list of all TStreamerElement
4007 /// objects for this class version.
4008 /// - ULong_t* fElem; containing the preprocessed information
4009 /// by TStreamerInfo::Compile In case consecutive data members
4010 /// are of the same type, the Compile function declares the consecutive
4011 /// elements as one single element in fElems.
4012 ///
4013 /// Example with the class TAttLine:
4014 /// ~~~{.cpp}
4015 /// TClass::GetClass("TAttLine")->GetStreamerInfo()->ls(); produces;
4016 /// StreamerInfo for class: TAttLine, version=1
4017 /// short fLineColor offset= 4 type= 2 line color
4018 /// short fLineStyle offset= 6 type= 2 line style
4019 /// short fLineWidth offset= 8 type= 2 line width
4020 /// i= 0, fLineColor type= 22, offset= 4, len=3, method=0
4021 /// ~~~
4022 /// For I/O implementations (eg. XML) , one has to know the original name
4023 /// of the data member. This function can be used to return a pointer
4024 /// to the original TStreamerElement object corresponding to the j-th
4025 /// element of a compressed array in fElems.
4026 /// Parameters description:
4027 /// - i: the serial number in array fElem
4028 /// - j: the element number in the array of consecutive types
4029 /// In the above example the class TAttLine has 3 consecutive data members
4030 /// of the same type "short". Compile makes one single array of 3 elements.
4031 /// To access the TStreamerElement for the second element
4032 /// of this array, one can call:
4033 /// ~~~{.cpp}
4034 /// auto el = GetStreamerElementReal(0,1);
4035 /// auto membername = el->GetName();
4036 /// ~~~
4037 /// This function is typically called from TBuffer, TXmlBuffer.
4038 
4040 {
4041  ::Obsolete("TStreamerInfo::GetStreamerElementReal", "v5-34-20", "v6-00-02");
4042 
4043  if (i < 0 || i >= fNdata) return 0;
4044  if (j < 0) return 0;
4045  if (!fElements) return 0;
4046  TStreamerElement *se = (TStreamerElement*)fCompOpt[i]->fElem;
4047  if (!se) return 0;
4048  Int_t nelems = fElements->GetEntriesFast();
4049  for (Int_t ise=0;ise < nelems;ise++) {
4050  if (se != (TStreamerElement*)fElements->UncheckedAt(ise)) continue;
4051  if (ise+j >= nelems) return 0;
4052  return (TStreamerElement*)fElements->UncheckedAt(ise+j);
4053  }
4054  return 0;
4055 }
4056 
4057 ////////////////////////////////////////////////////////////////////////////////
4058 /// Get the value from inside a collection.
4059 
4060 template <typename T>
4062 {
4063  if (type>=kConv && type<kSTL) {
4064  type -= kConv;
4065  }
4066  switch (type) {
4067  // basic types
4068  case kBool: {Bool_t *val = (Bool_t*)ladd; return T(*val);}
4069  case kChar: {Char_t *val = (Char_t*)ladd; return T(*val);}
4070  case kShort: {Short_t *val = (Short_t*)ladd; return T(*val);}
4071  case kInt: {Int_t *val = (Int_t*)ladd; return T(*val);}
4072  case kLong: {Long_t *val = (Long_t*)ladd; return T(*val);}
4073  case kLong64: {Long64_t *val = (Long64_t*)ladd; return T(*val);}
4074  case kFloat: {Float_t *val = (Float_t*)ladd; return T(*val);}
4075  case kFloat16: {Float_t *val = (Float_t*)ladd; return T(*val);}
4076  case kDouble: {Double_t *val = (Double_t*)ladd; return T(*val);}
4077  case kDouble32: {Double_t *val = (Double_t*)ladd; return T(*val);}
4078  case kUChar: {UChar_t *val = (UChar_t*)ladd; return T(*val);}
4079  case kUShort: {UShort_t *val = (UShort_t*)ladd; return T(*val);}
4080  case kUInt: {UInt_t *val = (UInt_t*)ladd; return T(*val);}
4081  case kULong: {ULong_t *val = (ULong_t*)ladd; return T(*val);}
4082 #if defined(_MSC_VER) && (_MSC_VER <= 1200)
4083  case kULong64: {Long64_t *val = (Long64_t*)ladd; return T(*val);}
4084 #else
4085  case kULong64: {ULong64_t *val= (ULong64_t*)ladd; return T(*val);}
4086 #endif
4087  case kBits: {UInt_t *val = (UInt_t*)ladd; return T(*val);}
4088 
4089  // array of basic types array[8]
4090  case kOffsetL + kBool: {Bool_t *val = (Bool_t*)ladd; return T(val[k]);}
4091  case kOffsetL + kChar: {Char_t *val = (Char_t*)ladd; return T(val[k]);}
4092  case kOffsetL + kShort: {Short_t *val = (Short_t*)ladd; return T(val[k]);}
4093  case kOffsetL + kInt: {Int_t *val = (Int_t*)ladd; return T(val[k]);}
4094  case kOffsetL + kLong: {Long_t *val = (Long_t*)ladd; return T(val[k]);}
4095  case kOffsetL + kLong64: {Long64_t *val = (Long64_t*)ladd; return T(val[k]);}
4096  case kOffsetL + kFloat: {Float_t *val = (Float_t*)ladd; return T(val[k]);}
4097  case kOffsetL + kFloat16: {Float_t *val = (Float_t*)ladd; return T(val[k]);}
4098  case kOffsetL + kDouble: {Double_t *val = (Double_t*)ladd; return T(val[k]);}
4099  case kOffsetL + kDouble32:{Double_t *val = (Double_t*)ladd; return T(val[k]);}
4100  case kOffsetL + kUChar: {UChar_t *val = (UChar_t*)ladd; return T(val[k]);}
4101  case kOffsetL + kUShort: {UShort_t *val = (UShort_t*)ladd; return T(val[k]);}
4102  case kOffsetL + kUInt: {UInt_t *val = (UInt_t*)ladd; return T(val[k]);}
4103  case kOffsetL + kULong: {ULong_t *val = (ULong_t*)ladd; return T(val[k]);}
4104 #if defined(_MSC_VER) && (_MSC_VER <= 1200)
4105  case kOffsetL + kULong64: {Long64_t *val = (Long64_t*)ladd; return T(val[k]);}
4106 #else
4107  case kOffsetL + kULong64:{ULong64_t *val= (ULong64_t*)ladd; return T(val[k]);}
4108 #endif
4109 
4110 #define READ_ARRAY(TYPE_t) \
4111  { \
4112  Int_t sub_instance, index; \
4113  Int_t instance = k; \
4114  if (len) { \
4115  index = instance / len; \
4116  sub_instance = instance % len; \
4117  } else { \
4118  index = instance; \
4119  sub_instance = 0; \
4120  } \
4121  TYPE_t **val =(TYPE_t**)(ladd); \
4122  return T((val[sub_instance])[index]); \
4123  }
4124 
4125  // pointer to an array of basic types array[n]
4129  case kOffsetP + kInt_t: READ_ARRAY(Int_t)
4132  case kOffsetP + kFloat16_t:
4134  case kOffsetP + kDouble32_t:
4140 #if defined(_MSC_VER) && (_MSC_VER <= 1200)
4142 #else
4144 #endif
4145 
4146  // array counter //[n]
4147  case kCounter: {Int_t *val = (Int_t*)ladd; return T(*val);}
4148  }
4149  return 0;
4150 }
4151 
4152 
4153 
4154 template Double_t TStreamerInfo::GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const;
4155 template Long64_t TStreamerInfo::GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const;
4156 template LongDouble_t TStreamerInfo::GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const;
4157 
4158 ////////////////////////////////////////////////////////////////////////////////
4159 /// Return value of element i in object at pointer.
4160 /// The function may be called in two ways:
4161 /// - method1 len < 0: i is assumed to be the TStreamerElement number i in StreamerInfo
4162 /// - method2 len >= 0: i is the type, address of variable is directly pointer.
4163 
4164 template <typename T>
4165 T TStreamerInfo::GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const
4166 {
4167  char *ladd;
4168  Int_t atype;
4169  if (len >= 0) {
4170  ladd = pointer;
4171  atype = i;
4172  } else {
4173  if (i < 0) return 0;
4174  ladd = pointer + fCompFull[i]->fOffset;
4175  atype = fCompFull[i]->fNewType;
4176  len = fCompFull[i]->fElem->GetArrayLength();
4177  if (atype == kSTL) {
4178  TClass *newClass = fCompFull[i]->fElem->GetNewClass();
4179  if (newClass == 0) {
4180  newClass = fCompFull[i]->fElem->GetClassPointer();
4181  }
4182  TClass *innerClass = newClass->GetCollectionProxy()->GetValueClass();
4183  if (innerClass) {
4184  return 0; // We don't know which member of the class we would want.
4185  } else {
4186  TVirtualCollectionProxy *proxy = newClass->GetCollectionProxy();
4187  // EDataType is a subset of TStreamerInfo::EReadWrite
4188  atype = (TStreamerInfo::EReadWrite)proxy->GetType();
4189  TVirtualCollectionProxy::TPushPop pop(proxy,ladd);
4190  Int_t nc = proxy->Size();
4191  if (j >= nc) return 0;
4192  char *element_ptr = (char*)proxy->At(j);
4193  return GetTypedValueAux<T>(atype,element_ptr,0,1);
4194  }
4195  }
4196  }
4197  return GetTypedValueAux<T>(atype,ladd,j,len);
4198 }
4199 
4200 ////////////////////////////////////////////////////////////////////////////////
4201 
4202 template Double_t TStreamerInfo::GetTypedValueClones<Double_t>(TClonesArray *clones, Int_t i, Int_t j, int k, Int_t eoffset) const;
4203 template Long64_t TStreamerInfo::GetTypedValueClones(TClonesArray *clones, Int_t i, Int_t j, int k, Int_t eoffset) const;
4204 template LongDouble_t TStreamerInfo::GetTypedValueClones(TClonesArray *clones, Int_t i, Int_t j, int k, Int_t eoffset) const;
4205 
4206 template <typename T>
4208 {
4209  // return value of element i in object number j in a TClonesArray and eventually
4210  // element k in a sub-array.
4211 
4212  Int_t nc = clones->GetEntriesFast();
4213  if (j >= nc) return 0;
4214 
4215  char *pointer = (char*)clones->UncheckedAt(j);
4216  char *ladd = pointer + eoffset + fCompFull[i]->fOffset;
4217  return GetTypedValueAux<T>(fCompFull[i]->fType,ladd,k,((TStreamerElement*)fCompFull[i]->fElem)->GetArrayLength());
4218 }
4219 
4220 template Double_t TStreamerInfo::GetTypedValueSTL(TVirtualCollectionProxy *cont, Int_t i, Int_t j, int k, Int_t eoffset) const;
4221 template Long64_t TStreamerInfo::GetTypedValueSTL(TVirtualCollectionProxy *cont, Int_t i, Int_t j, int k, Int_t eoffset) const;
4222 template LongDouble_t TStreamerInfo::GetTypedValueSTL(TVirtualCollectionProxy *cont, Int_t i, Int_t j, int k, Int_t eoffset) const;
4223 
4224 ////////////////////////////////////////////////////////////////////////////////
4225 /// Return value of element i in object number j in a TClonesArray and eventually
4226 /// element k in a sub-array.
4227 
4228 template <typename T>
4230 {
4231  Int_t nc = cont->Size();
4232  if (j >= nc) return 0;
4233 
4234  char *pointer = (char*)cont->At(j);
4235  char *ladd = pointer + eoffset + fCompFull[i]->fOffset;
4236  return GetTypedValueAux<T>(fCompFull[i]->fType,ladd,k,((TStreamerElement*)fCompFull[i]->fElem)->GetArrayLength());
4237 }
4238 
4239 template Double_t TStreamerInfo::GetTypedValueSTLP(TVirtualCollectionProxy *cont, Int_t i, Int_t j, int k, Int_t eoffset) const;
4240 template Long64_t TStreamerInfo::GetTypedValueSTLP(TVirtualCollectionProxy *cont, Int_t i, Int_t j, int k, Int_t eoffset) const;
4241 template LongDouble_t TStreamerInfo::GetTypedValueSTLP(TVirtualCollectionProxy *cont, Int_t i, Int_t j, int k, Int_t eoffset) const;
4242 
4243 ////////////////////////////////////////////////////////////////////////////////
4244 /// Return value of element i in object number j in a TClonesArray and eventually
4245 /// element k in a sub-array.
4246 
4247 template <typename T>
4249 {
4250  Int_t nc = cont->Size();
4251 
4252  if (j >= nc) return 0;
4253 
4254  char **ptr = (char**)cont->At(j);
4255  char *pointer = *ptr;
4256 
4257  char *ladd = pointer + eoffset + fCompFull[i]->fOffset;
4258  return GetTypedValueAux<T>(fCompFull[i]->fType,ladd,k,((TStreamerElement*)fCompFull[i]->fElem)->GetArrayLength());
4259 }
4260 
4261 ////////////////////////////////////////////////////////////////////////////////
4262 /// Insert new members as expressed in the array of TSchemaRule(s).
4263 
4264 void TStreamerInfo::InsertArtificialElements(std::vector<const ROOT::TSchemaRule*> &rules)
4265 {
4266  if (rules.empty()) return;
4267 
4268  TIter next(fElements);
4269  UInt_t count = 0;
4270 
4271  for(auto rule : rules) {
4272  if( rule->IsRenameRule() || rule->IsAliasRule() )
4273  continue;
4274  next.Reset();
4275  TStreamerElement *element;
4276  while ((element = (TStreamerElement*) next())) {
4277  if ( rule->HasTarget( element->GetName() ) ) {
4278 
4279  // Check whether this is an 'attribute' rule.
4280  if ( rule->GetAttributes()[0] != 0 ) {
4281  TString attr( rule->GetAttributes() );
4282  attr.ToLower();
4283  if (attr.Contains("owner")) {
4284  if (attr.Contains("notowner")) {
4286  } else {
4288  }
4289  }
4290 
4291  }
4292  break;
4293  }
4294  }
4295 
4296  // NOTE: Before adding the rule we should check that the source do
4297  // existing in this StreamerInfo.
4298  const TObjArray *sources = rule->GetSource();
4299  TIter input(sources);
4300  TObject *src;
4301  while((src = input())) {
4302  if ( !GetElements()->FindObject(src->GetName()) ) {
4303  // Missing source.
4304 #if 0 // Don't warn about not activating the rule. If don't warn the user can
4305  // have more flexibility in specifiying when the rule applies and relying
4306  // on both the version number *and* the presence of the source members.
4307  // Activating this warning would for example mean that we need to carefully
4308  // tweak $ROOTSYS/etc/class.rules.
4309  TString ruleStr;
4310  rule->AsString(ruleStr);
4311  Warning("InsertArtificialElements","For class %s in StreamerInfo %d is missing the source data member %s when trying to apply the rule:\n %s",
4312  GetName(),GetClassVersion(),src->GetName(),ruleStr.Data());
4313  rule = 0;
4314 #endif
4315  break;
4316  }
4317  }
4318 
4319  if (!rule) continue;
4320 
4321  TStreamerArtificial *newel;
4322  typedef std::vector<TStreamerArtificial*> vec_t;
4323  vec_t toAdd;
4324 
4325  if (rule->GetTarget()==0) {
4326  TString newName;
4327  newName.Form("%s_rule%d",fClass->GetName(),count);
4328  newel = new TStreamerArtificial(newName,"",
4329  fClass->GetDataMemberOffset(newName),
4331  "void");
4333  newel->SetReadFunc( rule->GetReadFunctionPointer() );
4334  newel->SetReadRawFunc( rule->GetReadRawFunctionPointer() );
4335  toAdd.push_back(newel);
4336  } else {
4337  toAdd.reserve(rule->GetTarget()->GetEntries());
4338  TObjString * objstr = (TObjString*)(rule->GetTarget()->At(0));
4339  if (objstr) {
4340  TString newName = objstr->String();
4341  TString realDataName;
4342  if ( TDataMember* dm = fClass->GetDataMember( newName ) ) {
4343  TRealData::GetName(realDataName,dm);
4344  newel = new TStreamerArtificial(realDataName,"",
4345  fClass->GetDataMemberOffset(newName),
4347  fClass->GetDataMember( newName )->GetTypeName());
4348  newel->SetReadFunc( rule->GetReadFunctionPointer() );
4349  newel->SetReadRawFunc( rule->GetReadRawFunctionPointer() );
4350  toAdd.push_back(newel);
4351  } else {
4352  // This would be a completely new member (so it would need to be cached)
4353  // TOBEDONE
4354  }
4355  for(Int_t other = 1; other < rule->GetTarget()->GetEntries(); ++other) {
4356  objstr = (TObjString*)(rule->GetTarget()->At(other));
4357  if (objstr) {
4358  newName = objstr->String();
4359  if ( TDataMember* dm = fClass->GetDataMember( newName ) ) {
4360  TRealData::GetName(realDataName,dm);
4361  newel = new TStreamerArtificial(realDataName,"",
4362  fClass->GetDataMemberOffset(newName),
4364  fClass->GetDataMember( newName )->GetTypeName());
4365  toAdd.push_back(newel);
4366  }
4367  }
4368  }
4369  } // For each target of the rule
4370  }
4371  // Now find we with need to add them
4372  TIter s_iter(rule->GetSource());
4373  Int_t loc = -1;
4374  while( TObjString *s = (TObjString*)s_iter() ) {
4375  for(Int_t i = fElements->GetLast(); i >= 0 && (i+1) >= loc; --i) {
4376  if (s->String() == fElements->UncheckedAt(i)->GetName()) {
4377  if (loc == -1 || (i+1)>loc) {
4378  loc = i+1;
4379  }
4380  }
4381  }
4382  }
4383  if (loc == -1) {
4384  // Verify if the last one is not 'skipped'.
4385  for(Int_t i = fElements->GetLast(); i >= 0 && (i+1) >= loc; --i) {
4386  if ( ((TStreamerElement*)fElements->UncheckedAt(i))->GetNewType() != -2 ) {
4387  break;
4388  }
4389  loc = i;
4390  }
4391  }
4392  if (loc == -1) {
4393  for(vec_t::iterator iter = toAdd.begin(); iter != toAdd.end(); ++iter) {
4394  fElements->Add(*iter);
4395  }
4396  } else {
4397  R__TObjArray_InsertAt(fElements, toAdd, loc);
4398  }
4399  } // None of the target of the rule are on file.
4400 }
4401 
4402 ////////////////////////////////////////////////////////////////////////////////
4403 /// List the TStreamerElement list and also the precomputed tables
4404 /// if option contains the string "incOrig", also prints the original
4405 /// (non-optimized elements in the list of compiled elements.
4406 
4407 void TStreamerInfo::ls(Option_t *option) const
4408 {
4409  if (fClass && (fName != fClass->GetName())) {
4410  if (fClass->IsVersioned()) {
4411  Printf("\nStreamerInfo for conversion to %s from: %s, version=%d, checksum=0x%x",fClass->GetName(),GetName(),fClassVersion,GetCheckSum());
4412  } else {
4413  Printf("\nStreamerInfo for conversion to %s from: %s, checksum=0x%x",fClass->GetName(),GetName(),GetCheckSum());
4414  }
4415  } else {
4416  if (!fClass || fClass->IsVersioned()) {
4417  Printf("\nStreamerInfo for class: %s, version=%d, checksum=0x%x",GetName(),fClassVersion,GetCheckSum());
4418  } else {
4419  Printf("\nStreamerInfo for class: %s, checksum=0x%x",GetName(),GetCheckSum());
4420  }
4421  }
4422 
4423  if (fElements) {
4424  TIter next(fElements);
4425  TObject *obj;
4426  while ((obj = next()))
4427  obj->ls(option);
4428  }
4429  if (strstr(option,"full") != 0) {
4430  for (Int_t i=0; i < fNfulldata; ++i) {
4431  TStreamerElement *element = (TStreamerElement*)fCompFull[i]->fElem;
4432  TString sequenceType;
4433  element->GetSequenceType(sequenceType);
4434  // by definition of the loop (i+1) <= fNdata
4435  if (sequenceType.Length()) {
4436  sequenceType.Prepend(" [");
4437  sequenceType += "]";
4438  }
4439  Printf(" i=%2d, %-15s type=%3d, offset=%3d, len=%d, method=%ld%s",
4440  i,element->GetName(),fCompFull[i]->fType,fCompFull[i]->fOffset,fCompFull[i]->fLength,fCompFull[i]->fMethod,
4441  sequenceType.Data());
4442  }
4443 
4444  } else {
4445  Bool_t wantOrig = strstr(option,"incOrig") != 0;
4446  Bool_t optimized = kFALSE;
4447  for (Int_t i=0,j=0;i < fNdata;++i,++j) {
4448  TStreamerElement *element = (TStreamerElement*)fCompOpt[i]->fElem;
4449  TString sequenceType;
4450  element->GetSequenceType(sequenceType);
4451  // by definition of the loop (i+1) <= fNdata
4453  if (optimized) {
4454  // This was optimized.
4455  if (sequenceType.Length() != 0) {
4456  sequenceType += ',';
4457  }
4458  sequenceType += "optimized";
4459  }
4460  if (sequenceType.Length()) {
4461  sequenceType.Prepend(" [");
4462  sequenceType += "]";
4463  }
4464  Printf(" i=%2d, %-15s type=%3d, offset=%3d, len=%d, method=%ld%s",
4465  i,element->GetName(),fCompOpt[i]->fType,fCompOpt[i]->fOffset,fCompOpt[i]->fLength,fCompOpt[i]->fMethod,
4466  sequenceType.Data());
4467  if (optimized && wantOrig) {
4468  Bool_t done;
4469  do {
4470  element = (TStreamerElement*)fCompFull[j]->fElem;
4471  element->GetSequenceType(sequenceType);
4472  if (sequenceType.Length()) {
4473  sequenceType.Prepend(" [");
4474  sequenceType += "]";
4475  }
4476  Printf(" j=%2d, %-15s type=%3d, offset=%3d, len=%d, method=%ld%s",
4477  j,element->GetName(),fCompFull[j]->fType,fCompFull[j]->fOffset,fCompFull[j]->fLength,fCompFull[j]->fMethod,
4478  sequenceType.Data());
4479  ++j;
4480  done = j >= fNfulldata || ( (i+1 < fNdata) && fCompOpt[i+1]->fElem == fCompFull[j+1]->fElem );
4481  } while (!done);
4482 
4483  }
4484  }
4485  }
4486 }
4487 
4488 ////////////////////////////////////////////////////////////////////////////////
4489 /// An emulated object is created at address obj, if obj is null we
4490 /// allocate memory for the object.
4491 
4492 void* TStreamerInfo::New(void *obj)
4493 {
4494  //???FIX ME: What about varying length array elements?
4495 
4496  char* p = (char*) obj;
4497 
4498  TIter next(fElements);
4499 
4500  if (!p) {
4501  // Allocate and initialize the memory block.
4502  p = new char[fSize];
4503  memset(p, 0, fSize);
4504  }
4505 
4506  next.Reset();
4507  TStreamerElement* element = (TStreamerElement*) next();
4508 
4509  for (; element; element = (TStreamerElement*) next()) {
4510 
4511  // Skip elements which have not been allocated memory.
4512  if (element->GetOffset() == kMissing) {
4513  continue;
4514  }
4515 
4516  // Skip elements for which we do not have any class
4517  // information. FIXME: Document how this could happen.
4518  TClass* cle = element->GetClassPointer();
4519  if (!cle) {
4520  continue;
4521  }
4522 
4523  char* eaddr = p + element->GetOffset();
4524  Int_t etype = element->GetType();
4525 
4526  //cle->GetStreamerInfo(); //necessary in case "->" is not specified
4527 
4528  switch (etype) {
4529 
4530  case kAnyP:
4531  case kObjectP:
4532  case kSTLp:
4533  {
4534  // Initialize array of pointers with null pointers.
4535  char** r = (char**) eaddr;
4536  Int_t len = element->GetArrayLength();
4537  for (Int_t i = 0; i < len; ++i) {
4538  r[i] = 0;
4539  }
4540  }
4541  break;
4542 
4543  case kObjectp:
4544  case kAnyp:
4545  {
4546  // If the option "->" is given in the data member comment field
4547  // it is assumed that the object exists before reading data in,
4548  // so we create an object.
4549  if (cle != TClonesArray::Class()) {
4550  void** r = (void**) eaddr;
4551  *r = cle->New();
4552  } else {
4553  // In the case of a TClonesArray, the class name of
4554  // the contained objects must be specified in the
4555  // data member comment in this format:
4556  // TClonesArray* myVar; //->(className)
4557  const char* title = element->GetTitle();
4558  const char* bracket1 = strrchr(title, '(');
4559  const char* bracket2 = strrchr(title, ')');
4560  if (bracket1 && bracket2 && (bracket2 != (bracket1 + 1))) {
4561  Int_t len = bracket2 - (bracket1 + 1);
4562  char* clonesClass = new char[len+1];
4563  clonesClass[0] = '\0';
4564  strncat(clonesClass, bracket1 + 1, len);
4565  void** r = (void**) eaddr;
4566  *r = (void*) new TClonesArray(clonesClass);
4567  delete[] clonesClass;
4568  } else {
4569  //Warning("New", "No class name found for TClonesArray initializer in data member comment (expected \"//->(className)\"");
4570  void** r = (void**) eaddr;
4571  *r = (void*) new TClonesArray();
4572  }
4573  }
4574  }
4575  break;
4576 
4577  case kBase:
4578  {
4579  if (cle->Property() & kIsAbstract) {
4581  if (einfo) einfo->New(eaddr);
4582  } else {
4583  cle->New(eaddr);
4584  }
4585  break;
4586  }
4587  case kObject:
4588  case kAny:
4589  case kTObject:
4590  case kTString:
4591  case kTNamed:
4592  {
4593  cle->New(eaddr);
4594  }
4595  break;
4596 
4597  case kSTL:
4598  {
4599  if (strcmp(element->GetName(),"This")==0 &&
4600  !cle->GetCollectionProxy()) {
4601  // missing information, avoid infinite loop
4602  // by doing nothing ....
4603  } else {
4604  cle->New(eaddr);
4605  }
4606  }
4607  break;
4608 
4609  case kObject + kOffsetL:
4610  case kAny + kOffsetL:
4611  case kTObject + kOffsetL:
4612  case kTString + kOffsetL:
4613  case kTNamed + kOffsetL:
4614  case kSTL + kOffsetL:
4615  {
4616  Int_t size = cle->Size();
4617  char* r = eaddr;
4618  Int_t len = element->GetArrayLength();
4619  for (Int_t i = 0; i < len; ++i, r += size) {
4620  cle->New(r);
4621  }
4622  }
4623  break;
4624 
4625  } // switch etype
4626  } // for TIter next(fElements)
4627 
4628  for(int nbase = 0; nbase < fNVirtualInfoLoc; ++nbase) {
4629  *(TStreamerInfo**)(p + fVirtualInfoLoc[nbase]) = this;
4630  }
4631  ++fLiveCount;
4632  return p;
4633 }
4634 
4635 ////////////////////////////////////////////////////////////////////////////////
4636 /// An array of emulated objects is created at address ary, if ary is null,
4637 /// we allocate memory for the array.
4638 
4639 void* TStreamerInfo::NewArray(Long_t nElements, void *ary)
4640 {
4641  if (fClass == 0) {
4642  Error("NewArray", "TClass pointer is null!");
4643  return 0;
4644  }
4645 
4646  Int_t size = fClass->Size();
4647 
4648  char* p = (char*) ary;
4649 
4650  if (!p) {
4651  Long_t len = nElements * size + sizeof(Long_t)*2;
4652  p = new char[len];
4653  memset(p, 0, len);
4654  }
4655 
4656  // Store the array cookie
4657  Long_t* r = (Long_t*) p;
4658  r[0] = size;
4659  r[1] = nElements;
4660  char* dataBegin = (char*) &r[2];
4661 
4662  // Do a placement new for each element.
4663  p = dataBegin;
4664  for (Long_t cnt = 0; cnt < nElements; ++cnt) {
4665  New(p);
4666  p += size;
4667  } // for nElements
4668 
4669  return dataBegin;
4670 }
4671 
4672 
4673 #define DeleteBasicPointer(addr,element,name) \
4674  { \
4675  name **f = (name**)(addr); \
4676  int n = element->GetArrayLength() ? element->GetArrayLength() : 1;\
4677  for(int j=0;j<n;j++) { \
4678  delete [] f[j]; \
4679  f[j] = 0; \
4680  } \
4681  }
4682 
4683 ////////////////////////////////////////////////////////////////////////////////
4684 /// Internal part of the destructor.
4685 /// Destruct each of the datamembers in the same order
4686 /// as the implicit destructor would.
4687 
4688 void TStreamerInfo::DestructorImpl(void* obj, Bool_t dtorOnly)
4689 {
4690  R__ASSERT(obj != 0);
4691 
4692  char *p = (char*)obj;
4693 
4694  Int_t nelements = fElements->GetEntriesFast();
4695  //for (; ele; ele = (TStreamerElement*) next())
4696  for (Int_t elenum = nelements - 1; elenum >= 0; --elenum) {
4698  if (ele->GetOffset() == kMissing) continue;
4699  char* eaddr = p + ele->GetOffset();
4700 
4701 
4702  Int_t etype = ele->GetType();
4703 
4704  switch(etype) {
4720  case TStreamerInfo::kCharStar: DeleteBasicPointer(eaddr,ele,Char_t); continue;
4721  }
4722 
4723 
4724 
4725  TClass* cle = ele->GetClassPointer();
4726  if (!cle) continue;
4727 
4728 
4729  if (etype == kObjectp || etype == kAnyp) {
4730  // Destroy an array of pre-allocated objects.
4731  Int_t len = ele->GetArrayLength();
4732  if (!len) {
4733  len = 1;
4734  }
4735  void** r = (void**) eaddr;
4736  for (Int_t j = len - 1; j >= 0; --j) {
4737  if (r[j]) {
4738  cle->Destructor(r[j]);
4739  r[j] = 0;
4740  }
4741  }
4742  }
4743 
4744  if ((etype == kObjectP || etype == kAnyP || etype == kSTLp) && !ele->TestBit(TStreamerElement::kDoNotDelete)) {
4745  // Destroy an array of pointers to not-pre-allocated objects.
4746  Int_t len = ele->GetArrayLength();
4747  if (!len) {
4748  len = 1;
4749  }
4750  void** r = (void**) eaddr;
4751  for (Int_t j = len - 1; j >= 0; --j) {
4752  if (r[j]) {
4753  cle->Destructor(r[j]);
4754  r[j] = 0;
4755  }
4756  }
4757  }
4758 
4759  if (etype == kBase) {
4760  if (cle->Property() & kIsAbstract) {
4762  if (einfo) einfo->Destructor(eaddr, kTRUE);
4763  } else {
4764  cle->Destructor(eaddr, kTRUE);
4765  }
4766  }
4767 
4768  if (etype == kObject || etype == kAny ||
4769  etype == kTObject || etype == kTString || etype == kTNamed) {
4770  // A data member is destroyed, but not deleted.
4771  cle->Destructor(eaddr, kTRUE);
4772  }
4773 
4774  if (etype == kSTL) {
4775  // A data member is destroyed, but not deleted.
4777  if (!pr) {
4778  if (strcmp(ele->GetName(),"This")==0) {
4779  // missing information, avoid infinite loop
4780  // by doing nothing ....
4781  } else {
4782  cle->Destructor(eaddr, kTRUE);
4783  }
4784  } else {
4786  TVirtualCollectionProxy::TPushPop env(cle->GetCollectionProxy(), eaddr); // used for both this 'clear' and the 'clear' inside destructor.
4787  cle->GetCollectionProxy()->Clear(); // empty the collection without deleting the pointer
4788  pr->Destructor(eaddr, kTRUE);
4789  } else {
4790  pr->Destructor(eaddr, kTRUE);
4791  }
4792  }
4793  }
4794 
4795  if (etype == kObject + kOffsetL || etype == kAny + kOffsetL ||
4796  etype == kTObject + kOffsetL || etype == kTString + kOffsetL ||
4797  etype == kTNamed + kOffsetL || etype == kSTL + kOffsetL) {
4798  // For a data member which is an array of objects, we
4799  // destroy the objects, but do not delete them.
4800  Int_t len = ele->GetArrayLength();
4801  Int_t size = cle->Size();
4802  char* r = eaddr + (size * (len - 1));
4803  for (Int_t j = len - 1; j >= 0; --j, r -= size) {
4804  cle->Destructor(r, kTRUE);
4805  }
4806  }
4807  } // iter over elements
4808 
4809  if (!dtorOnly) {
4810  delete[] p;
4811  }
4812  --fLiveCount;
4813 }
4814 
4815 ////////////////////////////////////////////////////////////////////////////////
4816 /// Emulated destructor for this class.
4817 ///
4818 /// An emulated object is destroyed at address p.
4819 /// Destruct each of the datamembers in the same order
4820 /// as the implicit destructor would.
4821 
4822 void TStreamerInfo::Destructor(void* obj, Bool_t dtorOnly)
4823 {
4824  // Do nothing if passed a null pointer.
4825  if (obj == 0) return;
4826 
4827  char* p = (char*) obj;
4828 
4829  if (!dtorOnly && fNVirtualInfoLoc) {
4830  // !dtorOnly is used to filter out the case where this is called for
4831  // a base class or embeded object of the outer most class.
4832  TStreamerInfo *allocator = *(TStreamerInfo**)(p + fVirtualInfoLoc[0]);
4833  if (allocator != this) {
4834 
4835  Int_t baseoffset = allocator->GetClass()->GetBaseClassOffset(GetClass());
4836 
4837  p -= baseoffset;
4838  allocator->DestructorImpl(p, kFALSE);
4839  return;
4840  }
4841  }
4842  DestructorImpl(p, dtorOnly);
4843 }
4844 
4845 ////////////////////////////////////////////////////////////////////////////////
4846 /// Destroy an array of emulated objects, with optional delete.
4847 
4848 void TStreamerInfo::DeleteArray(void* ary, Bool_t dtorOnly)
4849 {
4850  // Do nothing if passed a null pointer.
4851  if (ary == 0) return;
4852 
4853  //???FIX ME: What about varying length arrays?
4854 
4855  Long_t* r = (Long_t*) ary;
4856  Long_t arrayLen = r[-1];
4857  Long_t size = r[-2];
4858  char* memBegin = (char*) &r[-2];
4859 
4860  char* p = ((char*) ary) + ((arrayLen - 1) * size);
4861  for (Long_t cnt = 0; cnt < arrayLen; ++cnt, p -= size) {
4862  // Destroy each element, but do not delete it.
4863  Destructor(p, kTRUE);
4864  } // for arrayItemSize
4865 
4866  if (!dtorOnly) {
4867  delete[] memBegin;
4868  }
4869 }
4870 
4871 ////////////////////////////////////////////////////////////////////////////////
4872 /// print value of element i in object at pointer
4873 /// The function may be called in two ways:
4874 /// -method1 len < 0
4875 /// i is assumed to be the TStreamerElement number i in StreamerInfo
4876 /// -method2 len >= 0
4877 /// i is the type
4878 /// address of variable is directly pointer.
4879 /// len is the number of elements to be printed starting at pointer.
4880 
4881 void TStreamerInfo::PrintValue(const char *name, char *pointer, Int_t i, Int_t len, Int_t lenmax) const
4882 {
4883  char *ladd;
4884  Int_t atype,aleng;
4885  printf(" %-15s = ",name);
4886 
4887  TStreamerElement * aElement = 0;
4888  Int_t *count = 0;
4889  if (len >= 0) {
4890  ladd = pointer;
4891  atype = i;
4892  aleng = len;
4893  } else {
4894  if (i < 0) {
4895  if (pointer==0) {
4896  printf("NULL\n");
4897  } else {
4898  const static TClassRef stringClass("string");
4899  if (fClass == stringClass) {
4900  std::string *st = (std::string*)(pointer);
4901  printf("%s\n",st->c_str());
4902  } else if (fClass == TString::Class()) {
4903  TString *st = (TString*)(pointer);
4904  printf("%s\n",st->Data());
4905  } else {
4906  printf("(%s*)0x%lx\n",GetName(),(ULong_t)pointer);
4907  }
4908  }
4909  return;
4910  }
4911  ladd = pointer + fCompFull[i]->fOffset;
4912  atype = fCompFull[i]->fNewType;
4913  aleng = fCompFull[i]->fLength;
4914  aElement = (TStreamerElement*)fCompFull[i]->fElem;
4915  count = (Int_t*)(pointer+fCompFull[i]->fMethod);
4916  }
4917  if (aleng > lenmax) aleng = lenmax;
4918 
4919  PrintValueAux(ladd,atype,aElement,aleng,count);
4920  printf("\n");
4921 }
4922 
4923 ////////////////////////////////////////////////////////////////////////////////
4924 /// Print value of element i in a TClonesArray.
4925 
4926 void TStreamerInfo::PrintValueClones(const char *name, TClonesArray *clones, Int_t i, Int_t eoffset, Int_t lenmax) const
4927 {
4928  if (!clones) {printf(" %-15s = \n",name); return;}
4929  printf(" %-15s = ",name);
4930  Int_t nc = clones->GetEntriesFast();
4931  if (nc > lenmax) nc = lenmax;
4932 
4933  Int_t offset = eoffset + fCompFull[i]->fOffset;
4934  TStreamerElement *aElement = (TStreamerElement*)fCompFull[i]->fElem;
4935  int aleng = fCompFull[i]->fLength;
4936  if (aleng > lenmax) aleng = lenmax;
4937 
4938  for (Int_t k=0;k < nc;k++) {
4939  char *pointer = (char*)clones->UncheckedAt(k);
4940  char *ladd = pointer+offset;
4941  Int_t *count = (Int_t*)(pointer+fCompFull[i]->fMethod);
4942  PrintValueAux(ladd,fCompFull[i]->fNewType,aElement, aleng, count);
4943  if (k < nc-1) printf(", ");
4944  }
4945  printf("\n");
4946 }
4947 
4948 ////////////////////////////////////////////////////////////////////////////////
4949 /// Print value of element i in a TClonesArray.
4950 
4951 void TStreamerInfo::PrintValueSTL(const char *name, TVirtualCollectionProxy *cont, Int_t i, Int_t eoffset, Int_t lenmax) const
4952 {
4953  if (!cont) {printf(" %-15s = \n",name); return;}
4954  printf(" %-15s = ",name);
4955  Int_t nc = cont->Size();
4956  if (nc > lenmax) nc = lenmax;
4957 
4958  Int_t offset = eoffset + fCompFull[i]->fOffset;
4959  TStreamerElement *aElement = (TStreamerElement*)fCompFull[i]->fElem;
4960  int aleng = fCompFull[i]->fLength;
4961  if (aleng > lenmax) aleng = lenmax;
4962 
4963  for (Int_t k=0;k < nc;k++) {
4964  char *pointer = (char*)cont->At(k);
4965  char *ladd = pointer+offset;
4966  Int_t *count = (Int_t*)(pointer+fCompFull[i]->fMethod);
4967  PrintValueAux(ladd,fCompFull[i]->fNewType,aElement, aleng, count);
4968  if (k < nc-1) printf(", ");
4969  }
4970  printf("\n");
4971 }
4972 
4973 ////////////////////////////////////////////////////////////////////////////////
4974 /// Stream an object of class TStreamerInfo.
4975 
4976 void TStreamerInfo::Streamer(TBuffer &R__b)
4977 {
4978  UInt_t R__s, R__c;
4979  if (R__b.IsReading()) {
4980  Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
4981  fOldVersion = R__v;
4982  if (R__v > 1) {
4983  //R__b.ReadClassBuffer(TStreamerInfo::Class(), this, R__v, R__s, R__c);
4984  R__b.ClassBegin(TStreamerInfo::Class(), R__v);
4985  R__b.ClassMember("TNamed");
4986  TNamed::Streamer(R__b);
4987  fName = TClassEdit::GetLong64_Name( fName.Data() ).c_str();
4988  R__b.ClassMember("fCheckSum","UInt_t");
4989  R__b >> fCheckSum;
4990  R__b.ClassMember("fClassVersion","Int_t");
4991  R__b >> fClassVersion;
4993  R__b.ClassMember("fElements","TObjArray*");
4994  R__b >> fElements;
4996  R__b.SetBufferOffset(R__s+R__c+sizeof(UInt_t));
5000 
5001  if (R__b.GetParent() && R__b.GetVersionOwner() < 50000)
5002  {
5003  // In some older files, the type of the TStreamerElement was not
5004  // as we (now) expect.
5005  Int_t nobjects = fElements->GetEntriesFast();
5006  TClass *basic = TStreamerBasicType::Class();
5007  for (Int_t i = 0; i < nobjects; i++) {
5008  TStreamerElement *el = (TStreamerElement*)fElements->UncheckedAt(i);
5009  TStreamerElement *rel = 0;
5010  if ( el->IsA() == basic ) {
5011  switch (el->GetType()) {
5012  default: break; /* nothing */
5013  case TStreamerInfo::kObject: /*61*/
5014  rel = new TStreamerObject(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5015  break;
5016  case TStreamerInfo::kAny: /*62*/
5017  rel = new TStreamerObjectAny(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5018  break;
5019  case TStreamerInfo::kObjectp: /* 63 */
5020  rel = new TStreamerObjectPointer(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5021  break;
5022  case TStreamerInfo::kObjectP: /* 64 */
5023  rel = new TStreamerObjectPointer(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5024  break;
5025  case TStreamerInfo::kTString: /* 65 */
5026  rel = new TStreamerObject(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5027  break;
5028  }
5029  if (rel) {
5030  (*fElements)[i] = rel;
5031  delete el;
5032  }
5033  }
5034  }
5035  }
5036  return;
5037  }
5038  //====process old versions before automatic schema evolution
5039  TNamed::Streamer(R__b);
5040  fName = TClassEdit::GetLong64_Name( fName.Data() ).c_str();
5041  R__b >> fCheckSum;
5042  R__b >> fClassVersion;
5044  R__b >> fElements;
5045  R__b.CheckByteCount(R__s, R__c, TStreamerInfo::IsA());
5046  } else {
5047  R__c = R__b.WriteVersion(TStreamerInfo::IsA(), kTRUE);
5049  R__b.ClassMember("TNamed");
5050  TNamed::Streamer(R__b);
5051  R__b.ClassMember("fCheckSum","UInt_t");
5052  R__b << fCheckSum;
5053  R__b.ClassMember("fClassVersion","Int_t");
5054  R__b << ((fClassVersion > 0) ? fClassVersion : -fClassVersion);
5055 
5056  //------------------------------------------------------------------------
5057  // Stream only non-artificial streamer elements
5058  //////////////////////////////////////////////////////////////////////////
5059 
5060  R__b.ClassMember("fElements","TObjArray*");
5061 #if NOTYET
5062  if (has_no_artificial_member) {
5063  R__b << fElements;
5064  } else
5065 #endif
5066  {
5068  Int_t nobjects = fElements->GetEntriesFast();
5069  TObjArray store( *fElements );
5070  TStreamerElement *el;
5071  for (Int_t i = 0; i < nobjects; i++) {
5073  if( el != 0 && (el->IsA() == TStreamerArtificial::Class() || el->TestBit(TStreamerElement::kRepeat))) {
5074  fElements->RemoveAt( i );
5075  } else if( el !=0 && (el->TestBit(TStreamerElement::kCache) && !el->TestBit(TStreamerElement::kWrite)) ) {
5076  fElements->RemoveAt( i );
5077  }
5078  }
5079  fElements->Compress();
5080  R__b << fElements;
5081  R__ASSERT(!fElements->IsOwner());
5082  *fElements = store;
5083  }
5085  R__b.SetByteCount(R__c, kTRUE);
5086  }
5087 }
5088 
5089 ////////////////////////////////////////////////////////////////////////////////
5090 /// Mark the classindex of the current file as using this TStreamerInfo.
5091 /// This function is deprecated and its functionality is now done by
5092 /// the overloads of TBuffer::TagStreamerInfo.
5093 
5095 {
5096  if (file) {
5097  // If the value of the atomic is kFALSE (equal to expected), change its value
5098  // to kTRUE and return true. Leave it as it is otherwise and return false.
5099  static std::atomic<Bool_t> onlyonce(kFALSE);
5100  Bool_t expected = kFALSE;
5101  if (onlyonce.compare_exchange_strong(expected,kTRUE)) {
5102  Warning("TagFile","This function is deprecated, use TBuffer::TagStreamerInfo instead");
5103  }
5104  TArrayC *cindex = file->GetClassIndex();
5105  Int_t nindex = cindex->GetSize();
5106  if (fNumber < 0 || fNumber >= nindex) {
5107  Error("TagFile","StreamerInfo: %s number: %d out of range[0,%d] in file: %s",
5108  GetName(),fNumber,nindex,file->GetName());
5109  return;
5110  }
5111  if (cindex->fArray[fNumber] == 0) {
5112  cindex->fArray[0] = 1;
5113  cindex->fArray[fNumber] = 1;
5114  }
5115  }
5116 }
5117 
5118 ////////////////////////////////////////////////////////////////////////////////
5119 
5120 #ifdef DOLOOP
5121 #undef DOLOOP
5122 #endif
5123 #define DOLOOP for (k = 0, pointer = arr[0]; k < narr; pointer = arr[++k])
5124 
5125 namespace {
5126  static void PrintCR(int j,Int_t aleng, UInt_t ltype)
5127  {
5128  if (j == aleng-1) printf("\n");
5129  else {
5130  printf(", ");
5131  if (j%ltype == ltype-1) printf("\n ");
5132  }
5133  }
5134 }
5135 
5136 ////////////////////////////////////////////////////////////////////////////////
5137 /// print value of element in object at pointer, type atype, leng aleng or *count
5138 /// The function may be called in two ways:
5139 /// -method1 len < 0
5140 /// i is assumed to be the TStreamerElement number i in StreamerInfo
5141 /// -method2 len >= 0
5142 /// i is the type
5143 /// address of variable is directly pointer.
5144 /// len is the number of elements to be printed starting at pointer.
5145 
5146 void TStreamerInfo::PrintValueAux(char *ladd, Int_t atype, TStreamerElement *aElement, Int_t aleng, Int_t *count)
5147 {
5148  int j;
5149 
5150  //assert(!((kOffsetP + kChar) <= atype && atype <= (kOffsetP + kBool) && count == 0));
5151  switch (atype) {
5152  // basic types
5153  case kBool: {Bool_t *val = (Bool_t* )ladd; printf("%d" ,*val); break;}
5154  case kChar: {Char_t *val = (Char_t* )ladd; printf("%d" ,*val); break;}
5155  case kShort: {Short_t *val = (Short_t* )ladd; printf("%d" ,*val); break;}
5156  case kInt: {Int_t *val = (Int_t* )ladd; printf("%d" ,*val); break;}
5157  case kLong: {Long_t *val = (Long_t* )ladd; printf("%ld",*val); break;}
5158  case kLong64: {Long64_t *val = (Long64_t* )ladd; printf("%lld",*val); break;}
5159  case kFloat: {Float_t *val = (Float_t* )ladd; printf("%f" ,*val); break;}
5160  case kFloat16: {Float_t *val = (Float_t* )ladd; printf("%f" ,*val); break;}
5161  case kDouble: {Double_t *val = (Double_t* )ladd; printf("%g" ,*val); break;}
5162  case kDouble32: {Double_t *val = (Double_t* )ladd; printf("%g" ,*val); break;}
5163  case kUChar: {UChar_t *val = (UChar_t* )ladd; printf("%u" ,*val); break;}
5164  case kUShort: {UShort_t *val = (UShort_t* )ladd; printf("%u" ,*val); break;}
5165  case kUInt: {UInt_t *val = (UInt_t* )ladd; printf("%u" ,*val); break;}
5166  case kULong: {ULong_t *val = (ULong_t* )ladd; printf("%lu",*val); break;}
5167  case kULong64: {ULong64_t *val = (ULong64_t*)ladd; printf("%llu",*val); break;}
5168  case kBits: {UInt_t *val = (UInt_t* )ladd; printf("%d" ,*val); break;}
5169 
5170  // array of basic types array[8]
5171  case kOffsetL + kBool: {Bool_t *val = (Bool_t* )ladd; for(j=0;j<aleng;j++) { printf("%c " ,val[j]); PrintCR(j,aleng,20); } break;}
5172  case kOffsetL + kChar: {Char_t *val = (Char_t* )ladd; for(j=0;j<aleng;j++) { printf("%c " ,val[j]); PrintCR(j,aleng,20); } break;}
5173  case kOffsetL + kShort: {Short_t *val = (Short_t* )ladd; for(j=0;j<aleng;j++) { printf("%d " ,val[j]); PrintCR(j,aleng,10); } break;}
5174  case kOffsetL + kInt: {Int_t *val = (Int_t* )ladd; for(j=0;j<aleng;j++) { printf("%d " ,val[j]); PrintCR(j,aleng,10); } break;}
5175  case kOffsetL + kLong: {Long_t *val = (Long_t* )ladd; for(j=0;j<aleng;j++) { printf("%ld ",val[j]); PrintCR(j,aleng, 5); } break;}
5176  case kOffsetL + kLong64: {Long64_t *val = (Long64_t* )ladd; for(j=0;j<aleng;j++) { printf("%lld ",val[j]);PrintCR(j,aleng, 5); } break;}
5177  case kOffsetL + kFloat: {Float_t *val = (Float_t* )ladd; for(j=0;j<aleng;j++) { printf("%f " ,val[j]); PrintCR(j,aleng, 5); } break;}
5178  case kOffsetL + kFloat16: {Float_t *val = (Float_t* )ladd; for(j=0;j<aleng;j++) { printf("%f " ,val[j]); PrintCR(j,aleng, 5); } break;}
5179  case kOffsetL + kDouble: {Double_t *val = (Double_t* )ladd; for(j=0;j<aleng;j++) { printf("%g " ,val[j]); PrintCR(j,aleng, 5); } break;}
5180  case kOffsetL + kDouble32:{Double_t *val = (Double_t* )ladd; for(j=0;j<aleng;j++) { printf("%g " ,val[j]); PrintCR(j,aleng, 5); } break;}
5181  case kOffsetL + kUChar: {UChar_t *val = (UChar_t* )ladd; for(j=0;j<aleng;j++) { printf("%u " ,val[j]); PrintCR(j,aleng,20); } break;}
5182  case kOffsetL + kUShort: {UShort_t *val = (UShort_t* )ladd; for(j=0;j<aleng;j++) { printf("%u " ,val[j]); PrintCR(j,aleng,10); } break;}
5183  case kOffsetL + kUInt: {UInt_t *val = (UInt_t* )ladd; for(j=0;j<aleng;j++) { printf("%u " ,val[j]); PrintCR(j,aleng, 5); } break;}
5184  case kOffsetL + kULong: {ULong_t *val = (ULong_t* )ladd; for(j=0;j<aleng;j++) { printf("%lu ",val[j]); PrintCR(j,aleng, 5); } break;}
5185  case kOffsetL + kULong64: {ULong64_t *val = (ULong64_t*)ladd; for(j=0;j<aleng;j++) { printf("%llu ",val[j]);PrintCR(j,aleng, 5); } break;}
5186  case kOffsetL + kBits: {UInt_t *val = (UInt_t* )ladd; for(j=0;j<aleng;j++) { printf("%d " ,val[j]); PrintCR(j,aleng, 5); } break;}
5187 
5188  // pointer to an array of basic types array[n]
5189  case kOffsetP + kBool: {Bool_t **val = (Bool_t** )ladd; for(j=0;j<*count;j++) { printf("%d " ,(*val)[j]); PrintCR(j,aleng,20); } break;}
5190  case kOffsetP + kChar: {Char_t **val = (Char_t** )ladd; for(j=0;j<*count;j++) { printf("%d " ,(*val)[j]); PrintCR(j,aleng,20); } break;}
5191  case kOffsetP + kShort: {Short_t **val = (Short_t** )ladd; for(j=0;j<*count;j++) { printf("%d " ,(*val)[j]); PrintCR(j,aleng,10); } break;}
5192  case kOffsetP + kInt: {Int_t **val = (Int_t** )ladd; for(j=0;j<*count;j++) { printf("%d " ,(*val)[j]); PrintCR(j,aleng,10); } break;}
5193  case kOffsetP + kLong: {Long_t **val = (Long_t** )ladd; for(j=0;j<*count;j++) { printf("%ld ",(*val)[j]); PrintCR(j,aleng, 5); } break;}
5194  case kOffsetP + kLong64: {Long64_t **val = (Long64_t**)ladd; for(j=0;j<*count;j++) { printf("%lld ",(*val)[j]); PrintCR(j,aleng, 5); } break;}
5195  case kOffsetP + kFloat: {Float_t **val = (Float_t** )ladd; for(j=0;j<*count;j++) { printf("%f " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5196  case kOffsetP + kFloat16: {Float_t **val = (Float_t** )ladd; for(j=0;j<*count;j++) { printf("%f " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5197  case kOffsetP + kDouble: {Double_t **val = (Double_t**)ladd; for(j=0;j<*count;j++) { printf("%g " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5198  case kOffsetP + kDouble32:{Double_t **val = (Double_t**)ladd; for(j=0;j<*count;j++) { printf("%g " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5199  case kOffsetP + kUChar: {UChar_t **val = (UChar_t** )ladd; for(j=0;j<*count;j++) { printf("%u " ,(*val)[j]); PrintCR(j,aleng,20); } break;}
5200  case kOffsetP + kUShort: {UShort_t **val = (UShort_t**)ladd; for(j=0;j<*count;j++) { printf("%u " ,(*val)[j]); PrintCR(j,aleng,10); } break;}
5201  case kOffsetP + kUInt: {UInt_t **val = (UInt_t** )ladd; for(j=0;j<*count;j++) { printf("%u " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5202  case kOffsetP + kULong: {ULong_t **val = (ULong_t** )ladd; for(j=0;j<*count;j++) { printf("%lu ",(*val)[j]); PrintCR(j,aleng, 5); } break;}
5203  case kOffsetP + kULong64: {ULong64_t**val = (ULong64_t**)ladd; for(j=0;j<*count;j++){ printf("%llu ",(*val)[j]); PrintCR(j,aleng, 5); } break;}
5204 
5205  // array counter //[n]
5206  case kCounter: {Int_t *val = (Int_t*)ladd; printf("%d",*val); break;}
5207  // char *
5208  case kCharStar:{
5209  char **val = (char**)ladd;
5210  if (*val) printf("%s",*val);
5211  break;
5212  }
5213  // Class * derived from TObject with comment field //->
5214  case kObjectp: {
5215  TObject **obj = (TObject**)(ladd);
5217  printf("(%s*)%lx",el ? el->GetClass()->GetName() : "unknown_type",(Long_t)(*obj));
5218  break;
5219  }
5220 
5221  // Class* derived from TObject
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 kObject: {
5231  TObject *obj = (TObject*)(ladd);
5232  printf("%s",obj->GetName());
5233  break;
5234  }
5235 
5236  // Special case for TString, TObject, TNamed
5237  case kTString: {
5238  TString *st = (TString*)(ladd);
5239  printf("%s",st->Data());
5240  break;
5241  }
5242  case kTObject: {
5243  TObject *obj = (TObject*)(ladd);
5244  printf("%s",obj->GetName());
5245  break;
5246  }
5247  case kTNamed: {
5248  TNamed *named = (TNamed*) (ladd);
5249  printf("%s/%s",named->GetName(),named->GetTitle());
5250  break;
5251  }
5252 
5253  // Class * not derived from TObject with comment field //->
5254  case kAnyp: {
5255  TObject **obj = (TObject**)(ladd);
5257  printf("(%s*)0x%lx",el ? el->GetClass()->GetName() : "unknown_type",(Long_t)(*obj));
5258  break;
5259  }
5260 
5261  // Class* not derived from TObject
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  // Any Class not derived from TObject
5269  case kOffsetL + kObjectp:
5270  case kOffsetL + kObjectP:
5271  case kAny: {
5272  printf("printing kAny case (%d)",atype);
5273 // if (aElement) {
5274 // TMemberStreamer *pstreamer = aElement->GetStreamer();
5275 // if (pstreamer == 0) {
5276 // //printf("ERROR, Streamer is null\n");
5277 // //aElement->ls();
5278 // break;
5279 // }
5280 // //(*pstreamer)(b,ladd,0);
5281 // }
5282  break;
5283  }
5284  // Base Class
5285  case kBase: {
5286  printf("printing kBase case (%d)",atype);
5287  //aElement->ReadBuffer(b,pointer);
5288  break;
5289  }
5290 
5291  case kOffsetL + kObject:
5292  case kOffsetL + kTString:
5293  case kOffsetL + kTObject:
5294  case kOffsetL + kTNamed:
5295  case kStreamer: {
5296  printf("printing kStreamer case (%d)",atype);
5297 // TMemberStreamer *pstreamer = aElement->GetStreamer();
5298 // if (pstreamer == 0) {
5299 // //printf("ERROR, Streamer is null\n");
5300 // //aElement->ls();
5301 // break;
5302 // }
5303 // //UInt_t start,count;
5304 // //b.ReadVersion(&start, &count);
5305 // //(*pstreamer)(b,ladd,0);
5306 // //b.CheckByteCount(start,count,IsA());
5307  break;
5308  }
5309 
5310  case kStreamLoop: {
5311  printf("printing kStreamLoop case (%d)",atype);
5312 // TMemberStreamer *pstreamer = aElement->GetStreamer();
5313 // if (pstreamer == 0) {
5314 // //printf("ERROR, Streamer is null\n");
5315 // //aElement->ls();
5316 // break;
5317 // }
5318  //Int_t *counter = (Int_t*)(count);
5319  //UInt_t start,count;
5320  ///b.ReadVersion(&start, &count);
5321  //(*pstreamer)(b,ladd,*counter);
5322  //b.CheckByteCount(start,count,IsA());
5323  break;
5324  }
5325  case kSTL: {
5326  if (aElement) {
5327  static TClassRef stringClass("string");
5328  if (ladd && aElement->GetClass() == stringClass) {
5329  std::string *st = (std::string*)(ladd);
5330  printf("%s",st->c_str());
5331  } else {
5332  printf("(%s*)0x%lx",aElement->GetClass()->GetName(),(Long_t)(ladd));
5333  }
5334  } else {
5335  printf("(unknown_type*)0x%lx",(Long_t)(ladd));
5336  }
5337  break;
5338  }
5339  }
5340 }
5341 
5342 ////////////////////////////////////////////////////////////////////////////////
5343 ///function called by the TClass constructor when replacing an emulated class
5344 ///by the real class
5345 
5346 void TStreamerInfo::Update(const TClass *oldcl, TClass *newcl)
5347 {
5348  TStreamerElement *element;
5349  TIter nextElement(GetElements());
5350  while ((element = (TStreamerElement*)nextElement())) {
5351  element->Update(oldcl,newcl);
5352  }
5353  for (Int_t i=0;i < fNslots;i++) {
5354  fComp[i].Update(oldcl,newcl);
5355  }
5356 }
5357 
5358 ////////////////////////////////////////////////////////////////////////////////
5359 /// Update the TClass pointer cached in this object.
5360 
5362 {
5363  if (fType != -1) {
5364  if (fClass == oldcl)
5365  fClass = newcl;
5366  else if (fClass == 0)
5367  fClass = TClass::GetClass(fClassName);
5368  }
5369 }
5370 
5371 ////////////////////////////////////////////////////////////////////////////////
5372 /// Generate emulated collection proxy for a given class.
5373 
5375 TStreamerInfo::GenEmulatedProxy(const char* class_name, Bool_t silent)
5376 {
5377  return TCollectionProxyFactory::GenEmulatedProxy(class_name, silent);
5378 }
5379 
5380 ////////////////////////////////////////////////////////////////////////////////
5381 /// Generate emulated class streamer for a given collection class.
5382 
5384 TStreamerInfo::GenEmulatedClassStreamer(const char* class_name, Bool_t silent)
5385 {
5386  return TCollectionProxyFactory::GenEmulatedClassStreamer(class_name, silent);
5387 }
5388 
5389 ////////////////////////////////////////////////////////////////////////////////
5390 /// Generate proxy from static functions.
5391 
5393 TStreamerInfo::GenExplicitProxy( const ::ROOT::TCollectionProxyInfo &info, TClass *cl )
5394 {
5396 }
5397 
5398 ////////////////////////////////////////////////////////////////////////////////
5399 /// Generate class streamer from static functions.
5400 
5402 TStreamerInfo::GenExplicitClassStreamer( const ::ROOT::TCollectionProxyInfo &info, TClass *cl )
5403 {
5405 }
Bool_t HasRuleWithSourceClass(const TString &source) const
Return True if we have any rule whose source class is &#39;source&#39;.
const int ndata
Describe Streamer information for one class version.
Definition: TStreamerInfo.h:47
Small helper to read a TBuffer containing a TClonesArray into any valid collection.
Int_t GetOffset(const char *) const
Return the offset of the data member as indicated by this StreamerInfo.
virtual const char * BaseName(const char *pathname)
Base name of a file name. Base name of /user/root is root.
Definition: TSystem.cxx:928
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:51
virtual void * New(void *obj=0)=0
virtual Bool_t IsTransient() const
Return kTRUE if the element represent an entity that is not written to the disk (transient members...
void SetBufferOffset(Int_t offset=0)
Definition: TBuffer.h:88
virtual Int_t GetCollectionType() const =0
Bool_t IsReading() const
Definition: TBuffer.h:81
Int_t fClassVersion
Class version identifier.
Definition: TStreamerInfo.h:97
Bool_t IsForeign() const
Return kTRUE is the class is Foreign (the class does not have a Streamer method). ...
Definition: TClass.cxx:5550
TList * GetListOfBases()
Return list containing the TBaseClass(es) of a class.
Definition: TClass.cxx:3438
static std::atomic< Int_t > fgCount
Number of TStreamerInfo instances.
const char * GetCountClass() const
An array of TObjects.
Definition: TObjArray.h:39
static void R__TObjArray_InsertBefore(TObjArray *arr, TObject *newobj, TObject *oldobj)
const char * GetTypeNameBasic() const
Return type name of this element in case the type name is not a standard basic type, return the basic type name known to CINT.
virtual void ClassBegin(const TClass *, Version_t=-1)=0
T GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const
Return value of element i in object at pointer.
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition: TObject.cxx:892
virtual void SetOffset(Int_t offset)
TString GetTypeName()
Get basic type of typedef, e,g.
Definition: TDataType.cxx:149
Version_t fOldVersion
! Version of the TStreamerInfo object read from the file
ROOT::ESTLType IsSTLCont(std::string_view type)
type : type name: vector<list<classA,allocator>,allocator> result: 0 : not stl container code of cont...
long long Long64_t
Definition: RtypesCore.h:69
virtual Int_t GetProperties() const
static void PrintValueAux(char *ladd, Int_t atype, TStreamerElement *aElement, Int_t aleng, Int_t *count)
print value of element in object at pointer, type atype, leng aleng or *count The function may be cal...
void BuildEmulated(TFile *file)
Create an Emulation TStreamerInfo object.
TStreamerInfoActions::TActionSequence * fWriteMemberWiseVecPtr
! List of write action resulting from the compilation for use in member wise streaming.
short Version_t
Definition: RtypesCore.h:61
TStreamerElement * GetStreamerElement(const char *datamember, Int_t &offset) const
Return the StreamerElement of "datamember" inside our class or any of its base classes.
virtual Bool_t CompareContent(TClass *cl, TVirtualStreamerInfo *info, Bool_t warn, Bool_t complete, TFile *file)=0
const char * GetFullTypeName() const
Get full type description of data member, e,g.: "class TDirectory*".
TLine * line
virtual TClass * GetClass() const =0
Collectable string class.
Definition: TObjString.h:32
float Float_t
Definition: RtypesCore.h:53
Equal to TDataType&#39;s kchar.
virtual void SetSize(Int_t dsize)
const char Option_t
Definition: RtypesCore.h:62
virtual TClass * GetValueClass() const =0
virtual void Delete(Option_t *option="")
Remove all objects from the array AND delete all heap based objects.
Definition: TObjArray.cxx:328
All ROOT classes may have RTTI (run time type identification) support added.
Definition: TDataMember.h:33
TObject * GetParent() const
Return pointer to parent of this buffer.
Definition: TBuffer.cxx:229
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
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
T GetTypedValueSTL(TVirtualCollectionProxy *cont, Int_t i, Int_t j, Int_t k, Int_t eoffset) const
Return value of element i in object number j in a TClonesArray and eventually element k in a sub-arra...
Int_t GetUnitSize() const
Get the sizeof the underlying type of the data member (i.e.
unsigned short UShort_t
Definition: RtypesCore.h:36
#define gDirectory
Definition: TDirectory.h:218
Bool_t TestBit(UInt_t f) const
Definition: TObject.h:173
virtual TClass * GetClassPointer() const
Returns a pointer to the TClass of this element.
virtual void SetName(const char *name)
Change (i.e.
Definition: TNamed.cxx:128
TArrayC * GetClassIndex() const
Definition: TFile.h:186
TStreamerElement * GetStreamerElementReal(Int_t i, Int_t j) const
Obsolete: this routine is obsolete and should not longer be used.
UInt_t GetBaseCheckSum()
TVirtualStreamerInfo * GetStreamerInfo(Int_t version=0) const
returns a pointer to the TVirtualStreamerInfo object for version If the object does not exist...
Definition: TClass.cxx:4326
void Update(const TClass *oldcl, TClass *newcl)
Update the TClass pointer cached in this object.
static TClassStreamer * GenEmulatedClassStreamer(const char *class_name, Bool_t silent)
Generate emulated class streamer for a given collection class.
A ROOT file is a suite of consecutive data records (TKey instances) with a well defined format...
Definition: TFile.h:45
virtual Int_t GetEntries() const
Definition: TCollection.h:92
const char * GetTypeName() const
Get type of data member, e,g.: "class TDirectory*" -> "TDirectory".
Buffer base class used for serializing objects.
Definition: TBuffer.h:40
Bool_t HasInterpreterInfo() const
Definition: TClass.h:374
TClassStreamer * GetStreamer() const
Return the Streamer Class allowing streaming (if any).
Definition: TClass.cxx:2817
virtual void SetTypeName(const char *name)
static const char * filename()
#define R__ASSERT(e)
Definition: TError.h:98
virtual Int_t CheckByteCount(UInt_t startpos, UInt_t bcnt, const TClass *clss)=0
#define gROOT
Definition: TROOT.h:352
TList * GetListOfDataMembers(Bool_t load=kTRUE)
Return list containing the TDataMembers of a class.
Definition: TClass.cxx:3529
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition: TString.h:582
void SetReadFunc(ROOT::TSchemaRule::ReadFuncPtr_t val)
void ForceWriteInfo(TFile *file, Bool_t force=kFALSE)
Recursively mark streamer infos for writing to a file.
void PrintValueClones(const char *name, TClonesArray *clones, Int_t i, Int_t eoffset, Int_t lenmax=1000) const
Print value of element i in a TClonesArray.
void * New(void *obj=0)
An emulated object is created at address obj, if obj is null we allocate memory for the object...
Basic string class.
Definition: TString.h:137
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition: TClass.cxx:2800
Int_t GetArrayLength() const
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
void Reset()
Definition: TClassRef.h:76
virtual void Clear(const char *opt="")=0
const Bool_t kFALSE
Definition: Rtypes.h:92
Int_t GenerateHeaderFile(const char *dirname, const TList *subClasses=0, const TList *extrainfos=0)
Generate header file for the class described by this TStreamerInfo the function is called by TFile::M...
Cache the value in memory than is not part of the object but is accessible via a SchemaRule.
static const char * GetElementCounterStart(const char *dmTitle)
Given a comment/title declaring an array counter, for example: //[fArraySize] array of size fArraySiz...
Int_t fNdata
!number of optimized elements
bool IsSTLBitset(const char *type)
Return true is the name is std::bitset<number> or bitset<number>
virtual void SetArrayDim(Int_t dim)
Set number of array dimensions.
ULong_t * fVirtualInfoLoc
![fNVirtualInfoLoc] Location of the pointer to the TStreamerInfo inside the object (when emulated) ...
TString & Prepend(const char *cs)
Definition: TString.h:604
Abstract base class for accessing the data-members of a class.
virtual UInt_t WriteVersion(const TClass *cl, Bool_t useBcnt=kFALSE)=0
TObject * At(Int_t idx) const
Definition: TObjArray.h:167
Int_t GetBaseVersion()
Int_t GetArrayDim() const
TClass * GetActualClass(const void *obj) const
Assuming that obj points to (the part of) an object that is of the type described by this streamerInf...
virtual EDataType GetType() const =0
Bool_t MatchLegacyCheckSum(UInt_t checksum) const
Return true if the checksum passed as argument is one of the checksum value produced by the older che...
void GetSequenceType(TString &type) const
Fill type with the string representation of sequence information including &#39;cached&#39;,&#39;repeat&#39;,&#39;write&#39; or &#39;nodelete&#39;.
virtual void SetMaxIndex(Int_t dim, Int_t max)
set maximum index for array with dimension dim
virtual void ForceWriteInfo(TFile *file, Bool_t force=kFALSE)=0
void Destructor(void *p, Bool_t dtorOnly=kFALSE)
Emulated destructor for this class.
static Proxy_t * GenExplicitProxy(const ::ROOT::TCollectionProxyInfo &info, TClass *cl)
Generate proxy from static functions.
void DeleteArray(void *p, Bool_t dtorOnly=kFALSE)
Destroy an array of emulated objects, with optional delete.
void PrintValue(const char *name, char *pointer, Int_t i, Int_t len, Int_t lenmax=1000) const
print value of element i in object at pointer The function may be called in two ways: -method1 len < ...
void Reset()
Definition: TCollection.h:161
TCompInfo ** fCompFull
![fElements->GetEntries()]
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition: TObject.cxx:732
TClass * GetClass() const
Definition: TClassRef.h:75
virtual TObject * FindObject(const char *name) const
Find an object in this list using its name.
Definition: TList.cxx:496
void ComputeSize()
Compute total size of all persistent elements of the class.
TStreamerInfoActions::TActionSequence * fReadMemberWise
! List of read action resulting from the compilation for use in member wise streaming.
Int_t fSize
!size of the persistent class
Int_t GetBaseClassOffset(const TClass *toBase, void *address=0, bool isDerivedObject=true)
Definition: TClass.cxx:2695
virtual void ClassMember(const char *, const char *=0, Int_t=-1, Int_t=-1)=0
TObject * Last() const
Return the object in the last filled slot. Returns 0 if no entries.
Definition: TObjArray.cxx:478
Bool_t IsBasic() const
Return true if data member is a basic type, e.g. char, int, long...
virtual Int_t GetClassVersion() const =0
virtual TVirtualCollectionProxy * GenEmulatedProxy(const char *class_name, Bool_t silent)
Generate emulated collection proxy for a given class.
friend class TClonesArray
Definition: TObject.h:214
#define READ_ARRAY(TYPE_t)
Int_t GetVersion() const
Definition: TFile.h:205
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.
The TNamed class is the base class for all named ROOT classes.
Definition: TNamed.h:33
virtual TVirtualCollectionProxy * GenExplicitProxy(const ::ROOT::Detail::TCollectionProxyInfo &info, TClass *cl)
Generate proxy from static functions.
virtual TObject * FindObject(const char *name) const
Find an object in this collection using its name.
Definition: TObjArray.cxx:395
virtual Int_t GetVersionOwner() const =0
ECheckSum
Definition: TClass.h:102
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:4409
Long_t Property() const
Get property description word. For meaning of bits see EProperty.
Bool_t IsLoaded() const
Return true if the shared library of this class is currently in the a process&#39;s memory.
Definition: TClass.cxx:5515
Int_t GetDelta()
Get offset from "this" to part of base class.
Definition: TBaseClass.cxx:74
#define DeleteBasicPointer(addr, element, name)
void Clear()
Clear string without changing its capacity.
Definition: TString.cxx:1139
std::string ResolveTypedef(const char *tname, bool resolveAll=false)
const char * GetCountClass() const
virtual void SetNewClass(TClass *cl)
EState GetState() const
Definition: TClass.h:443
Int_t fNfulldata
!number of elements
TString & Append(const char *cs)
Definition: TString.h:492
std::vector< std::vector< double > > Data
virtual void Destructor(void *p, Bool_t dtorOnly=kFALSE) const
Long_t GetThisOffset() const
Definition: TRealData.h:59
TStreamerInfoActions::TActionSequence * fReadObjectWise
! List of read action resulting from the compilation.
TDataType * GetDataType() const
Definition: TDataMember.h:74
virtual TClassStreamer * GenExplicitClassStreamer(const ::ROOT::Detail::TCollectionProxyInfo &info, TClass *cl)
Generate class streamer from static functions.
static UInt_t GenerateForwardDeclaration(FILE *fp, const char *clname, char *inclist, Bool_t implementEmptyClass, Bool_t needGenericTemplate, const TList *extrainfos)
Insert a (complete) forward declaration for the class &#39;clname&#39;.
static void R__WriteMoveConstructorBody(FILE *file, const TString &protoname, TIter &next)
Write down the body of the &#39;move&#39; constructor.
XFontStruct * id
Definition: TGX11.cxx:108
void SetCountClass(const char *clname)
void RegisterStreamerInfo(TVirtualStreamerInfo *info)
Register the StreamerInfo in the given slot, change the State of the TClass as appropriate.
Definition: TClass.cxx:6796
Bool_t operator!=(const TDatime &d1, const TDatime &d2)
Definition: TDatime.h:103
TVirtualStreamerInfo * GetBaseStreamerInfo() const
UInt_t fCheckSum
Checksum of original class.
Definition: TStreamerInfo.h:96
Int_t GetSizeElements() const
Return total size of all persistent elements of the class use GetSize if you want to get the real siz...
const TObjArray * GetStreamerInfos() const
Definition: TClass.h:447
void Obsolete(const char *method, const char *asOfVers, const char *removedFromVers) const
Use this method to declare a method obsolete.
Definition: TObject.cxx:980
void GenerateDeclaration(FILE *fp, FILE *sfp, const TList *subClasses, Bool_t top=kTRUE)
Write the Declaration of class.
std::string GetLong64_Name(const char *original)
Replace &#39;long long&#39; and &#39;unsigned long long&#39; by &#39;Long64_t&#39; and &#39;ULong64_t&#39;.
Definition: TClassEdit.cxx:816
static void AddInclude(FILE *fp, const char *header, Bool_t system, char *inclist)
Add an include statement, if it has not already been added.
virtual void ls(Option_t *option="") const
The ls function lists the contents of a class on stdout.
Definition: TObject.cxx:536
virtual void Update(const TClass *oldClass, TClass *newClass)
function called by the TClass constructor when replacing an emulated class by the real class ...
Eventhough BIT(13) is taken up by TObject (to preserverse forward compatibility)
T GetTypedValueSTLP(TVirtualCollectionProxy *cont, Int_t i, Int_t j, Int_t k, Int_t eoffset) const
Return value of element i in object number j in a TClonesArray and eventually element k in a sub-arra...
static T GetTypedValueAux(Int_t type, void *ladd, int k, Int_t len)
Get the value from inside a collection.
virtual void SetStreamer(TMemberStreamer *streamer)
set pointer to Streamer function for this element
Int_t GetMaxIndex(Int_t dim) const
Return maximum index for array dimension "dim".
A doubly linked list.
Definition: TList.h:47
void InsertArtificialElements(std::vector< const ROOT::TSchemaRule *> &rules)
Insert new members as expressed in the array of TSchemaRule(s).
Int_t GetType(Int_t id) const
static void R__WriteDestructorBody(FILE *file, TIter &next)
TClass * GetBaseClass(const char *classname)
Return pointer to the base class "classname".
Definition: TClass.cxx:2561
Int_t GetType() const
Definition: TDataType.h:70
virtual void Update(const TClass *oldClass, TClass *newClass)
function called by the TClass constructor when replacing an emulated class by the real class ...
void BuildRealData(void *pointer=0, Bool_t isTransient=kFALSE)
Build a full list of persistent data members.
Definition: TClass.cxx:1927
TClass * fClass
!pointer to class
void SetErrorMessage(const char *msg)
Int_t GetLast() const
Return index of last object in array.
Definition: TObjArray.cxx:527
static void R__TObjArray_InsertAt(TObjArray *arr, TObject *obj, Int_t at)
void ResetClassVersion(TClass *, const char *, Short_t)
Global function to update the version number.
TObjArray * fElements
Array of TStreamerElements.
virtual const char * GetInclude() const
UInt_t GenerateIncludes(FILE *fp, char *inclist, const TList *extrainfos)
Add to the header file, the #include need for this class.
virtual TObject * FindObject(const char *name) const
Must be redefined in derived classes.
Definition: TObject.cxx:379
virtual void AddAtAndExpand(TObject *obj, Int_t idx)
Add object at position idx.
Definition: TObjArray.cxx:221
TClass * GetClass() const
ROOT::R::TRInterface & r
Definition: Object.C:4
TVirtualStreamerInfo * FindStreamerInfo(TObjArray *arr, UInt_t checksum) const
Find the TVirtualStreamerInfo in the StreamerInfos corresponding to checksum.
Definition: TClass.cxx:6583
R__EXTERN TSystem * gSystem
Definition: TSystem.h:549
void BuildOld()
rebuild the TStreamerInfo structure
void Clear(Option_t *)
If opt cointains &#39;built&#39;, reset this StreamerInfo as if Build or BuildOld was never called on it (use...
UInt_t GetCheckSum() const
Int_t GetSize() const
Definition: TArray.h:49
Basic data type descriptor (datatype information is obtained from CINT).
Definition: TDataType.h:46
void SetCountClass(const char *clname)
void CallShowMembers(const void *obj, TMemberInspector &insp, Bool_t isTransient) const
Emulated a call ShowMembers() on the obj of this class type, passing insp and parent.
virtual TObject * RemoveAt(Int_t idx)
Remove object at index idx.
Definition: TObjArray.cxx:629
Int_t fOnFileClassVersion
!Class version identifier as stored on file.
Definition: TStreamerInfo.h:98
virtual Bool_t HasPointers() const =0
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition: TObject.cxx:487
TDataMember * GetDataMember() const
Definition: TRealData.h:57
void Destructor(void *obj, Bool_t dtorOnly=kFALSE)
Explicitly call destructor for object.
Definition: TClass.cxx:5029
void IgnoreTObjectStreamer(Bool_t ignore=kTRUE)
When the class kIgnoreTObjectStreamer bit is set, the automatically generated Streamer will not call ...
Definition: TClass.cxx:4535
const TMatches FindRules(const TString &source) const
Return all the rules that are about the given &#39;source&#39; class.
TMemberStreamer * GetStreamer() const
Return the associate streamer object.
Definition: TRealData.cxx:98
Int_t GetMaxIndex(Int_t i) const
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
Int_t GetDataMemberOffset(TDataMember *dm, TMemberStreamer *&streamer) const
Compute data member offset.
Int_t GetEntriesFast() const
Definition: TObjArray.h:66
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:918
Ssiz_t Length() const
Definition: TString.h:390
Int_t Size() const
Return size of object of this class.
Definition: TClass.cxx:5314
const TObjArray * GetTarget() const
Get the target data members of this rule (i.e. the in memory data member).
TSubString Strip(EStripType s=kTrailing, char c=' ') const
Return a substring of self stripped at beginning and/or end.
Definition: TString.cxx:1069
short Short_t
Definition: RtypesCore.h:35
The TRealData class manages the effective list of all data members for a given class.
Definition: TRealData.h:34
Bool_t CanIgnoreTObjectStreamer()
Definition: TClass.h:358
static void R__WriteConstructorBody(FILE *file, TIter &next)
Int_t GetArrayDim() const
Return number of array dimensions.
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:81
virtual void SetByteCount(UInt_t cntpos, Bool_t packInVersion=kFALSE)=0
long double LongDouble_t
Definition: RtypesCore.h:57
ROOT::ESTLType GetCollectionType() const
Return the &#39;type&#39; of the STL the TClass is representing.
Definition: TClass.cxx:2789
static TVirtualCollectionProxy * GenEmulatedProxy(const char *class_name, Bool_t silent)
Generate emulated collection proxy for a given class.
Long_t GetOffset() const
Get offset from "this".
Long_t Property() const
Set TObject::fBits and fStreamerType to cache information about the class.
Definition: TClass.cxx:5641
TString fName
Definition: TNamed.h:36
bool IsStdClass(const char *type)
return true if the class belongs to the std namespace
TString & String()
Definition: TObjString.h:52
virtual void AddAt(TObject *obj, Int_t idx)
Add object at position ids.
Definition: TObjArray.cxx:238
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:6020
Each class (see TClass) has a linked list of its base class(es).
Definition: TBaseClass.h:35
#define Printf
Definition: TGeoToOCC.h:18
TCompInfo * fComp
![fNslots with less than fElements->GetEntries()*1.5 used] Compiled info
TStreamerInfoActions::TActionSequence * fWriteMemberWise
! List of write action resulting from the compilation for use in member wise streaming.
Bool_t fIsBuilt
true if the StreamerInfo has been optimized
#define R__LOCKGUARD2(mutex)
PyObject * fType
TStreamerElement * fElem
Not Owned.
Definition: TStreamerInfo.h:59
T GetTypedValueClones(TClonesArray *clones, Int_t i, Int_t j, Int_t k, Int_t eoffset) const
virtual void Destructor(void *p, Bool_t dtorOnly=kFALSE)=0
const char * GetTrueTypeName() const
Get full type description of data member, e,g.: "class TDirectory*".
static UInt_t GenerateIncludeForTemplate(FILE *fp, const char *clname, char *inclist, Bool_t forward, const TList *extrainfos)
Add to the header file, the #include needed for the argument of this template.
TString & Remove(Ssiz_t pos)
Definition: TString.h:616
std::atomic< Bool_t > fIsCompiled
true if the StreamerInfo has been &#39;built&#39; (i.e. has all the StreamerElements it should have) ...
long Long_t
Definition: RtypesCore.h:50
Bool_t CallShowMembers(const void *obj, TMemberInspector &insp, Bool_t isTransient=kFALSE) const
Call ShowMembers() on the obj of this class type, passing insp and parent.
Definition: TClass.cxx:2101
Version_t GetClassVersion() const
Definition: TClass.h:382
void Build()
Build the I/O data structure for the current class version.
TObject * UncheckedAt(Int_t i) const
Definition: TObjArray.h:91
#define ClassImp(name)
Definition: Rtypes.h:279
double f(double x)
Int_t GetSize() const
Return total size of all persistent elements of the class (with offsets).
double Double_t
Definition: RtypesCore.h:55
virtual TObjArray * GetElements() const =0
Int_t fNslots
!total numbrer of slots in fComp.
TStreamerInfoActions::TActionSequence * fReadMemberWiseVecPtr
! List of read action resulting from the compilation for use in member wise streaming.
virtual Bool_t IsaPointer() const
TStreamerInfoActions::TActionSequence * fWriteObjectWise
! List of write action resulting from the compilation.
void RemoveStreamerInfo(Int_t slot)
Remove and delete the StreamerInfo in the given slot.
Definition: TClass.cxx:6820
Long_t GetDataMemberOffset(const char *membername) const
return offset for member name.
Definition: TClass.cxx:3239
virtual const char * GetFullName() const
Return element name including dimensions, if any Note that this function stores the name into a stati...
int type
Definition: TGX11.cxx:120
unsigned long long ULong64_t
Definition: RtypesCore.h:70
virtual Int_t GetSize() const
Returns size of this element in bytes.
void SetNewBaseClass(TClass *cl)
TList * GetListOfRealData() const
Definition: TClass.h:405
Bool_t HasDataMemberInfo() const
Definition: TClass.h:371
const char * GetParent() const
unsigned long ULong_t
Definition: RtypesCore.h:51
virtual Bool_t HasCounter() const
virtual Bool_t IsBase() const
Return kTRUE if the element represent a base class.
EDataType
Definition: TDataType.h:30
virtual void SetType(Int_t dtype)
Int_t fNVirtualInfoLoc
! Number of virtual info location to update.
virtual void * At(UInt_t idx)=0
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition: TString.h:567
const char * AsString() const
Return the date & time as a string (ctime() format).
Definition: TDatime.cxx:99
#define R__LOCKGUARD(mutex)
void InspectMember(const T &obj, const char *name, Bool_t isTransient)
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition: TClass.cxx:2871
void Compile()
loop on the TStreamerElement list regroup members with same type Store predigested information into l...
Bool_t IsPersistent() const
Definition: TDataMember.h:89
void TagFile(TFile *fFile)
Mark the classindex of the current file as using this TStreamerInfo.
#define name(a, b)
Definition: linkTestLib0.cpp:5
virtual TObject * Clone(const char *newname="") const
Make a clone of an object using the Streamer facility.
Definition: TNamed.cxx:63
const TList * GetStreamerInfoCache()
Returns the cached list of StreamerInfos used in this file.
Definition: TFile.cxx:1298
Mother of all ROOT objects.
Definition: TObject.h:58
TObjArray * GetElements() const
void ls(Option_t *option="") const
List the TStreamerElement list and also the precomputed tables if option contains the string "incOrig...
virtual void Init(TObject *obj=0)
Setup the element.
virtual void Inspect(TClass *cl, const char *parent, const char *name, const void *addr)
Int_t GetNewType() const
Int_t IsSTLContainer()
The return type is defined in TDictionary (kVector, kList, etc.)
virtual UInt_t Size() const =0
TClassRef is used to implement a permanent reference to a TClass object.
Definition: TClassRef.h:33
char Char_t
Definition: RtypesCore.h:29
Int_t GetClassVersion() const
static TString UpdateAssociativeToVector(const char *name)
If we have a map, multimap, set or multiset, plus unordered partners, and the key is a class...
virtual const char * GetTitle() const
Returns title of object.
Definition: TObject.cxx:459
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition: TClass.cxx:5541
Int_t GetOnFileClassVersion() const
An array of clone (identical) objects.
Definition: TClonesArray.h:32
Int_t fNumber
!Unique identifier
Definition: TStreamerInfo.h:99
void BuildCheck(TFile *file=0)
Check if built and consistent with the class dictionary.
virtual ~TStreamerInfo()
TStreamerInfo dtor.
const char * GetTypeName() const
Int_t GetNewType(Int_t id) const
virtual void ClassEnd(const TClass *)=0
const char * GetArrayIndex() const
If the data member is pointer and has a valid array size in its comments GetArrayIndex returns a stri...
TClass * GetNewClass() const
Int_t Size() const
Get size of basic typedef&#39;ed type.
Definition: TDataType.cxx:366
Bool_t IsVersioned() const
Definition: TClass.h:463
Char_t * fArray
Definition: TArrayC.h:32
std::string ShortType(const char *typeDesc, int mode)
Return the absolute type of typeDesc.
virtual void SetNewType(Int_t dtype)
static TStreamerBasicType * GetElementCounter(const char *countName, TClass *cl)
Get pointer to a TStreamerBasicType in TClass *cl static function.
Int_t GetEntries() const
Return the number of objects in array (i.e.
Definition: TObjArray.cxx:493
R__EXTERN Int_t gDebug
Definition: Rtypes.h:128
void PrintValueSTL(const char *name, TVirtualCollectionProxy *cont, Int_t i, Int_t eoffset, Int_t lenmax=1000) const
Print value of element i in a TClonesArray.
void * NewArray(Long_t nElements, void *ary=0)
An array of emulated objects is created at address ary, if ary is null, we allocate memory for the ar...
void Add(TObject *obj)
Definition: TObjArray.h:75
const Int_t kMaxLen
TCompInfo ** fCompOpt
![fNdata]
double result[121]
TDataMember * GetDataMember(const char *datamember) const
Return pointer to datamember object with name "datamember".
Definition: TClass.cxx:3211
void ResetBit(UInt_t f)
Definition: TObject.h:172
unsigned char UChar_t
Definition: RtypesCore.h:34
const ROOT::Detail::TSchemaRuleSet * GetSchemaRules() const
Return the set of the schema rules if any.
Definition: TClass.cxx:1828
UInt_t GetCheckSum(ECheckSum code=kCurrentCheckSum) const
Call GetCheckSum with validity check.
Definition: TClass.cxx:6031
virtual TClass * GetClassPointer() const
Returns a pointer to the TClass of this element.
virtual void Init(TObject *obj=0)
Setup the element.
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition: TObject.cxx:946
const Bool_t kIterBackward
Definition: TCollection.h:44
virtual void Compress()
Remove empty slots from array.
Definition: TObjArray.cxx:308
virtual const char * GetName() const
Returns name of object.
Definition: TObject.cxx:415
virtual Int_t GetSize() const
Definition: TCollection.h:95
Abstract Interface class describing Streamer information for one class.
virtual const char * GetName() const
Returns name of object.
Definition: TRealData.h:56
Int_t GetNumber() const
TVirtualStreamerInfo * FindStreamerInfoAbstractEmulated(UInt_t checksum) const
For the case where the requestor class is emulated and this class is abstract, returns a pointer to t...
Definition: TClass.cxx:4469
const Bool_t kTRUE
Definition: Rtypes.h:91
TClass * GetClass() const
Definition: TDataMember.h:73
virtual void SetTitle(const char *title="")
Change (i.e. set) the title of the TNamed.
Definition: TNamed.cxx:152
Int_t GetOffset() const
Bool_t IsaPointer() const
Return true if data member is a pointer.
static UInt_t GenerateClassPrefix(FILE *fp, const char *clname, Bool_t top, TString &protoname, UInt_t *numberOfClasses, Int_t implementEmptyClass=kFALSE, Bool_t needGenericTemplate=kFALSE)
Write the start of the class (forward) declaration.
Int_t GetType() const
void CopyCollectionProxy(const TVirtualCollectionProxy &)
Copy the argument.
Definition: TClass.cxx:2376
void SetReadRawFunc(ROOT::TSchemaRule::ReadRawFuncPtr_t val)
Bool_t IsObject() const
Definition: TRealData.h:60
TRealData * GetRealData(const char *name) const
Return pointer to TRealData element with name "name".
Definition: TClass.cxx:3265
const char * cnt
Definition: TXMLSetup.cxx:75
TObject * Clone(const char *newname="") const
Make a clone of an object using the Streamer facility.
Bool_t CompareContent(TClass *cl, TVirtualStreamerInfo *info, Bool_t warn, Bool_t complete, TFile *file)
Return True if the current StreamerInfo in cl or info is equivalent to this TStreamerInfo.
std::atomic< ULong_t > fLiveCount
! Number of outstanding pointer to this StreamerInfo.
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition: TObject.cxx:904
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.
virtual const char * GetTitle() const
Returns title of object.
Definition: TNamed.h:52
This class stores the date and time with a precision of one second in an unsigned 32 bit word (950130...
Definition: TDatime.h:39
TClass * GetClass() const
static void R__TObjArray_InsertAfter(TObjArray *arr, TObject *newobj, TObject *oldobj)
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition: TClass.cxx:4672
const char * Data() const
Definition: TString.h:349
Array of chars or bytes (8 bits per element).
Definition: TArrayC.h:29
EReadWrite
EReadWrite Enumerator Enum Constant Description kBase Base class element kOffsetL Fixed size array k...