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