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