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