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