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