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
85
87{
88 // Slide by one.
89 Int_t last = arr->GetLast();
90 arr->AddAtAndExpand(arr->At(last),last+1);
91 for(Int_t ind = last-1; ind >= at; --ind) {
92 arr->AddAt( arr->At(ind), ind+1);
93 };
94 arr->AddAt( obj, at);
95}
96
97static void R__TObjArray_InsertAt(TObjArray *arr, std::vector<TStreamerArtificial*> &objs, Int_t at)
98{
99 // Slide by enough.
100 Int_t offset = objs.size();
101 Int_t last = arr->GetLast();
102 arr->AddAtAndExpand(arr->At(last),last+offset);
103 for(Int_t ind = last-1; ind >= at; --ind) {
104 arr->AddAt( arr->At(ind), ind+offset);
105 };
106 for(size_t ins = 0; ins < objs.size(); ++ins) {
107 arr->AddAt(objs[ins], at+ins);
108 }
109}
110
112{
113 // Slide by one.
114 Int_t last = arr->GetLast();
115 Int_t at = 0;
116 while (at<last && arr->At(at) != oldobj) {
117 ++at;
118 }
119 ++at; // we found the object, insert after it
121}
122
124{
125 // Slide by one.
126 Int_t last = arr->GetLast();
127 Int_t at = 0;
128 while (at<last && arr->At(at) != oldobj) {
129 ++at;
130 }
132}
133
134enum class EUniquePtrOffset : char
135 {
136 kNA = 0,
137 kZero = 1,
138 kNonZero = 2
139 };
140
141////////////////////////////////////////////////////////////////////////////////
142/// Default ctor.
143
145{
146 fNumber = -2;
147 fClass = 0;
148 fElements = 0;
149 fComp = 0;
150 fCompFull = 0;
151 fCompOpt = 0;
152 fCheckSum = 0;
153 fNdata = 0;
154 fNfulldata= 0;
155 fNslots = 0;
156 fSize = 0;
157 fClassVersion = 0;
159 fOldVersion = Class()->GetClassVersion();
161 fVirtualInfoLoc = 0;
162
163 fReadObjectWise = 0;
164 fReadMemberWise = 0;
166 fReadText = 0;
170 fWriteText = 0;
171}
172
173////////////////////////////////////////////////////////////////////////////////
174/// Create a TStreamerInfo object.
175
178{
179 fgCount++;
181 fClass = cl;
182 fElements = new TObjArray();
183 fComp = 0;
184 fCompFull = 0;
185 fCompOpt = 0;
186 fCheckSum = 0;
187 fNdata = 0;
188 fNfulldata= 0;
189 fNslots = 0;
190 fSize = 0;
193 fOldVersion = Class()->GetClassVersion();
195 fVirtualInfoLoc = 0;
196
197 fReadObjectWise = 0;
198 fReadMemberWise = 0;
200 fReadText = 0;
204 fWriteText = 0;
205}
206
207////////////////////////////////////////////////////////////////////////////////
208/// TStreamerInfo dtor.
209
211{
212 // Note: If a StreamerInfo is loaded from a file and is the same information
213 // as an existing one, it is assigned the same "unique id" and we need to double
214 // check before removing it from the global list.
215 if (fNumber >=0 && gROOT->GetListOfStreamerInfo()->GetSize() > fNumber
216 && gROOT->GetListOfStreamerInfo()->At(fNumber) == this)
217 gROOT->GetListOfStreamerInfo()->RemoveAt(fNumber);
218
219 delete [] fComp; fComp = 0;
220 delete [] fCompFull; fCompFull = 0;
221 delete [] fCompOpt; fCompOpt = 0;
222 delete [] fVirtualInfoLoc; fVirtualInfoLoc =0;
223
224 delete fReadObjectWise;
225 delete fReadMemberWise;
227 delete fReadText;
228 delete fWriteObjectWise;
229 delete fWriteMemberWise;
231 delete fWriteText;
232
233 if (!fElements) return;
234 fElements->Delete();
235 delete fElements; fElements=0;
236}
237
238////////////////////////////////////////////////////////////////////////////////
239/// Makes sure kBuildOldUsed set once Build or BuildOld finishes.
240/// Makes sure kBuildRunning reset once Build finishes.
241
242namespace {
243 struct TPreventRecursiveBuildGuard {
244 TPreventRecursiveBuildGuard(TStreamerInfo* info): fInfo(info) {
245 fInfo->SetBit(TStreamerInfo::kBuildRunning);
246 fInfo->SetBit(TStreamerInfo::kBuildOldUsed);
247 }
249 fInfo->ResetBit(TStreamerInfo::kBuildOldUsed);
250 fInfo->ResetBit(TStreamerInfo::kBuildRunning);
251 }
252 TStreamerInfo* fInfo;
253 };
254
256 {
257 std::string localtypename(s->GetUnderlyingTypeName());
258 Int_t ndim = 0;
259 Int_t totaldim = 0;
261 Int_t datasize = 1;
263 std::vector<Int_t> dimensions;
264 static TClassRef string_classref("string");
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() || memClass == string_classref) {
284 } else {
286 }
287 } else {
288 if (memClass->GetCollectionProxy() || memClass == string_classref) {
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 if (dm->IsEnum()) {
645 // When introducing support for non-default sized enum, it was
646 // decided to keep the file format unchanged and to always
647 // store the enum constant as an int.
648 auto memType = enumdesc->GetUnderlyingType();
649 if (TDataType::GetDataType(memType)->Size() > 4) {
650 // 4 is the onfile space for an Int_t.
651 Error("Build",
652 "Discarding %s %s::%s because the underlying type (%s) for the enum %s is larger than 4 bytes "
653 "and may result in data loss.",
655 continue;
656 }
658 }
659 }
660 } else {
661 // try STL container or string
662 static const char* full_string_name = "basic_string<char,char_traits<char>,allocator<char> >";
663 if (!strcmp(dmType, "string") || !strcmp(dmType, "std::string") || !strcmp(dmType, full_string_name)) {
665 } else if (dm->IsSTLContainer()) {
666 TVirtualCollectionProxy *proxy = TClass::GetClass(dmType /* the underlying type */)->GetCollectionProxy();
667 if (proxy)
669 else
672 if (((TStreamerSTL*)element)->GetSTLtype() != ROOT::kSTLvector || hasCustomAlloc) {
673 auto printErrorMsg = [&](const char* category)
674 {
675 if (!isTransient)
676 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);
677 };
678 if (fClass->IsLoaded()) {
679 if (!element->GetClassPointer()->IsLoaded()) {
680 printErrorMsg("compiled");
681 delete element;
682 continue;
683 }
684 } else if (fClass->GetState() == TClass::kInterpreted) {
685 if (element->GetClassPointer()->GetCollectionProxy()->GetProperties() & TVirtualCollectionProxy::kIsEmulated) {
686 printErrorMsg("interpreted");
687 delete element;
688 continue;
689 }
690 }
691 }
692 } else {
694 if (!clm) {
695 if (!isTransient)
696 Error("Build", "%s, unknown type: %s %s\n", GetName(), dmFull, dmName);
697 continue;
698 }
699 if (isStdArray) {
700 // We do not want to rebuild the streamerinfo of an std::array<T,N> asking the dm->GetUnitSize(), but rather of T only.
701
702 dsize = clm->Size();
703 }
704 if (dmIsPtr) {
705 // a pointer to a class
706 if (dmCounter) {
707 element = new TStreamerLoop(dmName, dmTitle, offset, dm->GetArrayIndex(), dmCounter->GetClass()->GetName(), dmCounter->GetClass()->GetClassVersion(), dmFull);
708 } else {
709 if (clm->IsTObject()) {
711 } else {
713 if (!isTransient && !streamer && !clm->GetStreamer() && !clm->IsLoaded() && !clm->fIsSyntheticPair) {
714 Error("Build", "%s: %s has no streamer or dictionary, data member %s will not be saved",
715 GetName(), dmFull, dmName);
716 }
717 }
718 }
719 } else if (clm->IsTObject()) {
721 } else if ((clm == TString::Class()) && !dmIsPtr) {
723 } else {
725 if (!isTransient && !streamer && !clm->GetStreamer() && !clm->IsLoaded() && !clm->fIsSyntheticPair) {
726 Warning("Build", "%s: %s has no streamer or dictionary, data member \"%s\" will not be saved",
727 GetName(), dmFull, dmName);
728 }
729 }
730 }
731 }
732 if (!element) {
733 // If we didn't make an element, there is nothing to do.
734 continue;
735 }
736 if (!dsize) {
737 dsize = dm->GetUnitSize();
738 }
739 for (Int_t i = 0; i < ndim; ++i) {
740 auto maxIndex = 0;
742 else maxIndex = dm->GetMaxIndex(i);
743 element->SetMaxIndex(i, maxIndex);
744 }
745 element->SetArrayDim(ndim);
746 // If the datamember was a int[4] this is 4, if double[3][2] 3*2=6
747 Int_t narr = element->GetArrayLength();
748 if (!narr) {
749 narr = 1;
750 }
751 element->SetSize(dsize*narr);
752 element->SetStreamer(streamer);
753 if (!streamer) {
754 Int_t k = element->GetType();
755 if (k == kStreamer) {
756 // if ((k == kSTL) || (k == kSTL + kOffsetL) || (k == kStreamer) || (k == kStreamLoop))
757 // This is odd. Either we need to update the doc for TVirtualStreamerInfo::kNoType
758 // or change this value.
760 }
761 }
762
763 if ( !wasCompiled && (rules && rules.HasRuleWithSource( element->GetName(), kTRUE )) ) {
765
766 // If this is optimized to re-use TStreamerElement(s) in case of variable renaming,
767 // then we must revisit the code in TBranchElement::InitInfo that recalculate the
768 // fID (i.e. the index of the TStreamerElement to be used for streaming).
769
771 // Now that we are caching the unconverted element, we do not assign it to the real type even if we could have!
772 if (element->GetNewType()>0 /* intentionally not including base class for now */
773 && rules && !rules.HasRuleWithTarget( element->GetName(), kTRUE ) )
774 {
775 TStreamerElement *copy = (TStreamerElement*)element->Clone();
776 fElements->Add(copy);
778 cached = copy;
779
780 // 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() );
781 } else {
782 // If the element is just cached and not repeat, we need to inject an element
783 // to insure the writing.
787 writecopy->SetNewType( writecopy->GetType() );
788 writecopy->SetOffset( element->GetOffset() );
789 // Put the write element after the read element (that does caching).
791 }
793 // Get one of the potentially many rules applicable
794 // We should check that we don't have a second rule
795 auto r = rules.GetRuleWithSource(element->GetName());
796 assert(r && r->GetSource());
797 auto s = (ROOT::TSchemaRule::TSources *)(r->GetSource()->FindObject(element->GetName()));
798 assert(s);
799 UpdateFromRule(this, s, cached);
800 }
801
803 } // end of member loop
804
805 // Now add artificial TStreamerElement (i.e. rules that creates new members or set transient members).
807
808 if (needAllocClass) {
810 if (!infoalloc) {
811 if (!isTransient)
812 Error("Build","Could you create a TStreamerInfo for %s\n",TString::Format("%s@@%d",GetName(),GetClassVersion()).Data());
813 } else {
814 // Need to find the source of rules where an implicit conversion is requested.
815 if (rules) {
816 TIter next(infoalloc->fElements);
818 while ((alloc_element = (TStreamerElement *)next())) {
819 if (rules.HasRuleWithSource(alloc_element->GetName(), kTRUE)) {
820 auto r = rules.GetRuleWithSource(alloc_element->GetName());
821 assert(r && r->GetSource());
822 auto s = (ROOT::TSchemaRule::TSources *)(r->GetSource()->FindObject(alloc_element->GetName()));
823 assert(s);
825 }
826 }
827 }
828
829 // Tell clone we should rerun BuildOld
830 infoalloc->SetBit(kBuildOldUsed,false);
831 // Temporarily mark it as built to avoid the BuildCheck from removing
832 // Technically we only need to do this for the 'current' StreamerInfo
833 fIsBuilt = kTRUE;
834 infoalloc->BuildCheck();
835 infoalloc->BuildOld();
837 TClass *allocClass = infoalloc->GetClass();
838
839 {
840 TIter next(fElements);
842 while ((element = (TStreamerElement*) next())) {
843 if (element->TestBit(TStreamerElement::kRepeat) && element->IsaPointer()) {
844 TStreamerElement *other = (TStreamerElement*) infoalloc->GetElements()->FindObject(element->GetName());
845 if (other) {
847 }
848 }
849 }
850 infoalloc->GetElements()->Compress();
851 }
852 {
853 TIter next(fElements);
855 while ((element = (TStreamerElement*) next())) {
856 if (element->TestBit(TStreamerElement::kCache)) {
857 element->SetOffset(infoalloc->GetOffset(element->GetName()));
858 }
859 }
860 }
861
864
865 el = new TStreamerArtificial("@@dealloc","", 0, TStreamerInfo::kCacheDelete, allocClass->GetName());
866 fElements->Add( el );
867 }
868 }
869
870 //
871 // Make a more compact version.
872 //
873 Compile();
874 fIsBuilt = kTRUE;
875}
876
877////////////////////////////////////////////////////////////////////////////////
878/// Check if built and consistent with the class dictionary.
879/// This method is called by TFile::ReadStreamerInfo.
880
881void TStreamerInfo::BuildCheck(TFile *file /* = 0 */, Bool_t load /* = kTRUE */)
882{
884
886 if (!fClass) {
887 // fClassVersion should have been a Version_t and/or Version_t
888 // should have been an Int_t. Changing the on-file format
889 // of the StreamerInfo is 'hard' (for forward compatibility), so
890 // leave it as is for now.
892
893 // Case of a custom collection (the user provided a CollectionProxy
894 // for a class that is not an STL collection).
895 if (GetElements()->GetEntriesFast() == 1) {
897 Bool_t isstl = element && strcmp("This",element->GetName())==0;
898 if (isstl) {
899 if (element->GetTitle()[0] == '<') {
900 // We know the content.
901 TString content = element->GetTitle();
902 Int_t level = 1;
903 for(Int_t c = 1; c < content.Length(); ++c) {
904 if (content[c] == '<') ++level;
905 else if (content[c] == '>') --level;
906 if (level == 0) {
907 content.Remove(c+1);
908 break;
909 }
910 }
911 content.Prepend("vector");
913 TVirtualCollectionProxy *proxy = clequiv->GetCollectionProxy();
914 if (gDebug > 1)
915 Info("BuildCheck",
916 "Update the collection proxy of the class \"%s\" \n"
917 "\tto be similar to \"%s\".",
918 GetName(),content.Data());
920 } else {
921 Warning("BuildCheck", "\n\
922 The class %s had a collection proxy when written but it is not an STL\n \
923 collection and we did not record the type of the content of the collection.\n \
924 We will claim the content is a bool (i.e. no data will be read).",
925 GetName());
926 }
927 }
928 }
929
930 } else {
932 const bool isOldRVec = fClass->GetCollectionType() == ROOT::kROOTRVec && (fElements->GetEntries() == 1) &&
933 !strcmp(fElements->At(0)->GetName(), "fData");
935 // We have a collection that is indeed an STL collection,
936 // we know we don't need its streamerInfo.
938 return;
939 }
940 }
942
943 if (0 == strcmp("string",fClass->GetName())) {
944 // We know we do not need any offset check for a string
946 return;
947 }
948
949 const TObjArray *array = fClass->GetStreamerInfos();
950 TStreamerInfo* info = 0;
951
952 if (fClass->GetState() == TClass::kNoInfo && array->IsEmpty()) {
953 // We have an emulated class that has no TStreamerInfo, this
954 // means it was created to insert a (default) rule. Consequently
955 // the error message about the missing dictionary was not printed.
956 // For consistency, let's print it now!
957
958 ::Warning("TClass::TClass", "no dictionary for class %s is available", GetName());
959 }
960
961 // Case of a custom collection (the user provided a CollectionProxy
962 // for a class that is not an STL collection).
963 if (GetElements()->GetEntriesFast() == 1) {
965 Bool_t isstl = element && strcmp("This",element->GetName())==0;
966 if (isstl && !fClass->GetCollectionProxy()) {
967 if (element->GetTitle()[0] == '<') {
968 // We know the content.
969 TString content = element->GetTitle();
970 Int_t level = 1;
971 for(Int_t c = 1; c < content.Length(); ++c) {
972 if (content[c] == '<') ++level;
973 else if (content[c] == '>') --level;
974 if (level == 0) {
975 content.Remove(c+1);
976 break;
977 }
978 }
979 content.Prepend("vector");
981 TVirtualCollectionProxy *proxy = clequiv->GetCollectionProxy();
982 if (gDebug > 1)
983 Info("BuildCheck",
984 "Update the collection proxy of the class \"%s\" \n"
985 "\tto be similar to \"%s\".",
986 GetName(),content.Data());
988 } else {
989 Warning("BuildCheck", "\n\
990 The class %s had a collection proxy when written but it is not an STL\n \
991 collection and we did not record the type of the content of the collection.\n \
992 We will claim the content is a bool (i.e. no data will be read).",
993 GetName());
994 }
996 return;
997 }
998 }
999
1000 // If the user has not specified a class version (this _used to_
1001 // always be the case when the class is Foreign) or if the user
1002 // has specified a version to be explicitly 1. [We can not
1003 // distinguish the two cases using the information in the "on
1004 // file" StreamerInfo.]
1005
1007 if (fClass->IsLoaded() && fClass->GetClassVersion() >= 2) {
1008 // We know for sure that the user specified the version.
1009
1010 if (fOnFileClassVersion >= 2) {
1011 // The class version was specified when the object was
1012 // written
1013
1015
1016 } else {
1017 // The class version was not specified when the object was
1018 // written OR it was specified to be 1.
1019
1021 }
1022 } else if (fClass->IsLoaded() && !fClass->IsForeign()) {
1023 // We are in the case where the class has a Streamer function.
1024 // and fClass->GetClassVersion is 1, we still assume that the
1025 // Class Version is specified (to be one).
1026
1028
1029 } else if (fClass->IsLoaded() /* implied: && fClass->IsForeign() */ ) {
1030 // We are in the case of a Foreign class with no specified
1031 // class version.
1032
1034
1035 }
1036 else {
1037 // We are in the case of an 'emulated' class.
1038
1039 if (fOnFileClassVersion >= 2 && !isStdPair) {
1040 // The class version was specified when the object was
1041 // written
1042
1044
1045 } else {
1046 // The class version was not specified when the object was
1047 // written OR it was specified to be 1.
1048
1050
1051 TStreamerInfo* v1 = (TStreamerInfo*) array->At(1);
1052 if (v1) {
1053 if (fCheckSum != v1->GetCheckSum()) {
1054 fClassVersion = array->GetLast() + 1;
1055 }
1056 }
1057 }
1058 }
1059
1060 if (!searchOnChecksum) {
1061 if (fClassVersion < (array->GetEntriesFast() - 1)) {
1062 info = (TStreamerInfo*) array->At(fClassVersion);
1063 }
1064 } else {
1065 Int_t ninfos = array->GetEntriesFast() - 1;
1066 for (Int_t i = -1; i < ninfos; ++i) {
1067 info = (TStreamerInfo*) array->UncheckedAt(i);
1068 if (!info) {
1069 continue;
1070 }
1071 if (fCheckSum == info->GetCheckSum() && (info->GetOnFileClassVersion()==1 || info->GetOnFileClassVersion()==0)) {
1072 // We must match on the same checksum, an existing TStreamerInfo
1073 // for one of the 'unversioned' class layout (i.e. version was 1).
1074 fClassVersion = i;
1075 break;
1076 }
1077 info = 0;
1078 }
1079 if (info==0) {
1080 // Find an empty slot.
1081 ninfos = array->GetEntriesFast() - 1;
1082 Int_t slot = 1; // Start of Class version 1.
1083 while ((slot < ninfos) && (array->UncheckedAt(slot) != 0)) {
1084 ++slot;
1085 }
1087 }
1088 }
1089
1090 // NOTE: Should we check if the already existing info is the same as
1091 // the current one? Yes
1092 // In case a class (eg Event.h) has a TClonesArray of Tracks, it could be
1093 // that the old info does not have the class name (Track) in the data
1094 // member title. Set old title to new title
1095 if (info) {
1096 // We found an existing TStreamerInfo for our ClassVersion
1097 Bool_t match = kTRUE;
1098 Bool_t done = kFALSE;
1100 if (fClassVersion!=0 && !fClass->TestBit(TClass::kWarned) && (fClassVersion == info->GetClassVersion()) && (fCheckSum != info->GetCheckSum())) {
1101 // The TStreamerInfo's checksum is different from the checksum for the compile class.
1102
1103 match = kFALSE;
1104 oldIsNonVersioned = (info->fOnFileClassVersion==1 && info->fClassVersion != 1) || isStdPair;
1105
1107 // In the case where the read-in TStreamerInfo does not
1108 // match in the 'current' in memory TStreamerInfo for
1109 // a non foreign class (we can not get here if this is
1110 // a foreign class so we do not need to test it),
1111 // we need to add this one more test since the CINT behaviour
1112 // with enums changed over time, so verify the checksum ignoring
1113 // members of type enum. We also used to not count the //[xyz] comment
1114 // in the checksum, so test for that too.
1116 &&(info->GetCheckSum() == fClass->GetCheckSum() || fClass->MatchLegacyCheckSum(info->GetCheckSum()))
1117 )
1118 {
1119 match = kTRUE;
1120 }
1121 if (fOldVersion <= 2) {
1122 // Names of STL base classes was modified in vers==3. Allocators removed
1123 // (We could be more specific (see test for the same case below)
1124 match = kTRUE;
1125 }
1126 if (!match && CompareContent(0,info,kFALSE,kFALSE,file)) {
1127 match = kTRUE;
1128 }
1129#ifdef TEST_FOR_BACKWARD_COMPATIBILITY_ABSTRACT_CLASSES
1130 if (!match && file->GetVersion() < 51800 && fClass && (fClass->Property() & kIsAbstract)
1132 {
1133 // In some instances of old files (v5.17 and less), some StreamerInfo for
1134 // an abstract class where not written correctly, and add no
1135 // data member listed. If in addition one of the data member
1136 // was declared using a typedef _and_ the current class definition
1137 // uses a different typedef, we are unable to recalculate the
1138 // checksum as it was, because the information is missing from
1139 // the StreamerInfo, and for the same reason CompareContent can
1140 // not know whether this is okay or not ...
1141 //
1142 // Since this is such an unlikely scenario, let's complain
1143 // about it anyway (The class layout *may* have changed, we
1144 // don't know).
1145
1146 // if (this has only base classes) {
1147 // match = kTRUE;
1148 // }
1149 }
1150#endif
1151 } else {
1152 // The on-file TStreamerInfo's checksum differs from the checksum of a TStreamerInfo on another file.
1153
1154 match = kFALSE;
1155 oldIsNonVersioned = (info->fOnFileClassVersion==1 && info->fClassVersion != 1) || isStdPair;
1156
1157 // In the case where the read-in TStreamerInfo does not
1158 // match in the 'current' in memory TStreamerInfo for
1159 // a non foreign class (we can not get here if this is
1160 // a foreign class so we do not need to test it),
1161 // we need to add this one more test since the CINT behaviour
1162 // with enums changed over time, so verify the checksum ignoring
1163 // members of type enum. We also used to not count the //[xyz] comment
1164 // in the checksum, so test for that too.
1165 if (fCheckSum == info->GetCheckSum(TClass::kCurrentCheckSum)
1166 || info->MatchLegacyCheckSum(fCheckSum)
1167 || GetCheckSum(TClass::kCurrentCheckSum) == info->fCheckSum
1168 || MatchLegacyCheckSum(info->GetCheckSum())
1170 {
1171 match = kTRUE;
1172 }
1173 if (fOldVersion <= 2) {
1174 // Names of STL base classes was modified in vers==3. Allocators removed
1175 // (We could be more specific (see test for the same case below)
1176 match = kTRUE;
1177 }
1178 if (!match && CompareContent(0,info,kFALSE,kFALSE,file)) {
1179 match = kTRUE;
1180 }
1181 }
1182 }
1183 if (info->IsBuilt()) {
1185 fNumber = info->GetNumber();
1187 TObjArray* elems = info->GetElements();
1188 TStreamerElement* e1 = 0;
1189 TStreamerElement* e2 = 0;
1190 for (Int_t i = 0; i < nel; ++i) {
1192 e2 = (TStreamerElement*) elems->At(i);
1193 if (!e1 || !e2) {
1194 continue;
1195 }
1196 if (strlen(e1->GetTitle()) != strlen(e2->GetTitle())) {
1197 e2->SetTitle(e1->GetTitle());
1198 }
1199 }
1200
1201 done = kTRUE;
1202 } else {
1204 info = 0;
1205 }
1207 if (!match && !fClass->TestBit(TClass::kWarned)) {
1208 if (oldIsNonVersioned) {
1209 if (file) {
1210 Warning("BuildCheck", "\n\
1211 The class %s transitioned from not having a specified class version\n\
1212 to having a specified class version (the current class version is %d).\n\
1213 However too many different non-versioned layouts of the class have been\n\
1214 loaded so far. This prevent the proper reading of objects written with\n\
1215 the class layout version %d, in particular from the file:\n\
1216 %s.\n\
1217 To work around this issue, load fewer 'old' files in the same ROOT session.",
1219 } else {
1220 Warning("BuildCheck", "\n\
1221 The class %s transitioned from not having a specified class version\n\
1222 to having a specified class version (the current class version is %d).\n\
1223 However too many different non-versioned layouts of the class have been\n\
1224 loaded so far. This prevent the proper reading of objects written with\n\
1225 the class layout version %d.\n\
1226 To work around this issue, load fewer 'old' files in the same ROOT session.",
1228 }
1229 } else {
1230 if (file) {
1231 if (done) {
1232 Warning("BuildCheck", "\n\
1233 The StreamerInfo for version %d of class %s read from the file %s\n\
1234 has a different checksum than the previously loaded StreamerInfo.\n\
1235 Reading objects of type %s from the file %s \n\
1236 (and potentially other files) might not work correctly.\n\
1237 Most likely the version number of the class was not properly\n\
1238 updated [See ClassDef(%s,%d)].",
1239 fClassVersion, GetName(), file->GetName(), GetName(), file->GetName(), GetName(), fClassVersion);
1240 } else {
1241 Warning("BuildCheck", "\n\
1242 The StreamerInfo from %s does not match existing one (%s:%d)\n\
1243 The existing one has not been used yet and will be discarded.\n\
1244 Reading the file %s will work properly, however writing object of\n\
1245 type %s will not work properly. Most likely the version number\n\
1246 of the class was not properly updated [See ClassDef(%s,%d)].",
1248 }
1249 } else {
1250 if (done) {
1251 Warning("BuildCheck", "\n\
1252 The StreamerInfo for version %d of class %s\n\
1253 has a different checksum than the previously loaded StreamerInfo.\n\
1254 Reading objects of type %s\n\
1255 (and potentially other files) might not work correctly.\n\
1256 Most likely the version number of the class was not properly\n\
1257 updated [See ClassDef(%s,%d)].",
1259 } else {
1260 Warning("BuildCheck", "\n\
1261 The StreamerInfo does not match existing one (%s:%d)\n\
1262 The existing one has not been used yet and will be discarded.\n\
1263 Reading should work properly, however writing object of\n\
1264 type %s will not work properly. Most likely the version number\n\
1265 of the class was not properly updated [See ClassDef(%s,%d)].",
1267 }
1268 }
1269 }
1272 }
1273 if (done) {
1274 return;
1275 }
1276 }
1277 // The slot was free, however it might still be reserved for the current
1278 // loaded version of the class
1279 if (fClass->IsLoaded()
1281 && (fClassVersion != 0) // We don't care about transient classes
1283 && (fCheckSum != fClass->GetCheckSum())) {
1284
1285 // If the old TStreamerInfo matches the in-memory one when we either
1286 // - ignore the members of type enum
1287 // or
1288 // - ignore the comments annotation (//[xyz])
1289 // we can accept the old TStreamerInfo.
1290
1292
1294 if (warn) {
1295 warn = !CompareContent(fClass,0,kFALSE,kFALSE,file);
1296 }
1297#ifdef TEST_FOR_BACKWARD_COMPATIBILITY_ABSTRACT_CLASSES
1298 if (warn && file->GetVersion() < 51800 && fClass && (fClass->Property() & kIsAbstract)
1300 {
1301 // In some instances of old files (v5.17 and less), some StreamerInfo for
1302 // an abstract class where not written correctly, and add no
1303 // data member listed. If in addition one of the data member
1304 // was declared using a typedef _and_ the current class definition
1305 // uses a different typedef, we are unable to recalculate the
1306 // checksum as it was, because the information is missing from
1307 // the StreamerInfo, and for the same reason CompareContent can
1308 // not know whether this is okay or not ...
1309 //
1310 // Since this is such an unlikely scenario, let's complain
1311 // about it anyway (The class layout *may* have changed, we
1312 // don't know).
1313
1314 // if (this has only base classes) {
1315 // warn = kFALSE;
1316 // }
1317 }
1318#endif // TEST_FOR_BACKWARD_COMPATIBILITY
1319 if (warn && (fOldVersion <= 2)) {
1320 // Names of STL base classes was modified in vers==3. Allocators removed
1321 //
1323 TBaseClass* bc = 0;
1324 while ((bc = (TBaseClass*) nextBC())) {
1325 if (bc->GetClassPointer()->GetCollectionType()) {
1326 warn = kFALSE;
1327 }
1328 }
1329 }
1330 if (warn) {
1331 if (file) {
1332 Warning("BuildCheck", "\n\
1333 The StreamerInfo of class %s read from file %s\n\
1334 has the same version (=%d) as the active class but a different checksum.\n\
1335 You should update the version to ClassDef(%s,%d).\n\
1336 Do not try to write objects with the current class definition,\n\
1337 the files will not be readable.\n", GetName(), file->GetName(), fClassVersion, GetName(), fClassVersion + 1);
1338 } else {
1339 Warning("BuildCheck", "\n\
1340 The StreamerInfo of class %s \n\
1341 has the same version (=%d) as the active class but a different checksum.\n\
1342 You should update the version to ClassDef(%s,%d).\n\
1343 Do not try to write objects with the current class definition,\n\
1344 the files will not be readable.\n", GetName(), fClassVersion, GetName(), fClassVersion + 1);
1345 }
1348 }
1349 } else {
1350 if (!fClass->IsVersioned()) {
1351 Fatal("BuildCheck", "\n\
1352 The StreamerInfo of unversioned class %s \n\
1353 has the same version (=%d) as the active class but an old checksum.\n\
1354 This should not happen. An assert will follow.\n", GetName(), fClassVersion);
1355 }
1356 }
1357 }
1358 if (!fClass->IsLoaded() && this->fOnFileClassVersion>1)
1359 {
1360 ROOT::ResetClassVersion(fClass,(const char*)-1, this->fClassVersion);
1361 }
1362 }
1363 // FIXME: This code can never execute because Build() calls
1364 // TStreamerElement::Class()->IgnoreTObjectStreamer()
1365 // so our bits are never saved to the file.
1368 }
1369 if ((fClassVersion < -1) || (fClassVersion > 65000)) {
1370 printf("ERROR reading TStreamerInfo: %s fClassVersion=%d\n", GetName(), fClassVersion);
1372 fNumber = -1;
1373 return;
1374 }
1375
1378 && GetCheckSum() != fClass->GetCheckSum()
1380 // We got here, thus we are a perfect alias for the current streamerInfo,
1381 // but we might had odd v5 style name spelling, so let's prefer the
1382 // current one.
1384 if (maininfo) {
1385 fNumber = maininfo->GetNumber(); // For ReadStreamerInfo to record the expected slot.
1386 }
1388 return;
1389 }
1390
1392 ++fgCount;
1393 fNumber = fgCount;
1394
1395 // Since we just read this streamerInfo from file, it has already been built.
1396 fIsBuilt = kTRUE;
1397
1398 //add to the global list of StreamerInfo
1399 TObjArray* infos = (TObjArray*) gROOT->GetListOfStreamerInfo();
1400 infos->AddAtAndExpand(this, fNumber);
1401}
1402
1403////////////////////////////////////////////////////////////////////////////////
1404/// Create an Emulation TStreamerInfo object.
1405
1407{
1409
1411 R__ASSERT(file);
1412 Int_t fv = file->GetVersion()%100000;
1413 R__ASSERT(fv < 30000);
1414 fClassVersion = -1;
1415 fCheckSum = 2001;
1416 TObjArray *elements = GetElements();
1417 Int_t ndata = elements ? elements->GetEntriesFast() : 0;
1418 for (Int_t i=0;i < ndata;i++) {
1420 if (!element) break;
1421 int ty = element->GetType();
1422 if (ty < kChar || ty >kULong+kOffsetL) continue;
1423 if (ty == kLong) element->SetType(kInt);
1424 if (ty == kULong) element->SetType(kUInt);
1425 if (ty == kLong + kOffsetL) element->SetType(kInt + kOffsetL);
1426 if (ty == kULong + kOffsetL) element->SetType(kUInt + kOffsetL);
1427 if (ty <= kULong) continue;
1428 duName = element->GetName();
1429 duName.Append("QWERTY");
1430 TStreamerBasicType *bt = new TStreamerBasicType(duName, "", 0, kInt,"Int_t");
1431 {for (int j=ndata-1;j>=i;j--) {elements->AddAtAndExpand(elements->At(j),j+1);}}
1432 elements->AddAt(bt,i);
1433 ndata++;
1434 i++;
1435 }
1436 BuildOld();
1437}
1438
1439////////////////////////////////////////////////////////////////////////////////
1440/// Check if we can build this for foreign class - do we have some rules
1441/// to do that.
1442
1444{
1446
1447 if( !in_memory_cl || !in_memory_cl->GetSchemaRules() ) {
1448 return kFALSE;
1449 }
1450
1451 auto rules = in_memory_cl->GetSchemaRules()->FindRules( GetName(), fOnFileClassVersion, fCheckSum );
1452
1453 if( rules.empty() && !in_memory_cl->GetCollectionType() ) {
1454 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() );
1455 return kFALSE;
1456 }
1457
1458 fClass = const_cast<TClass*>(in_memory_cl);
1459
1460 return kTRUE;
1461}
1462
1463
1464namespace {
1465////////////////////////////////////////////////////////////////////////////////
1466/// Helper function for BuildOld
1468 {
1469 // Returns true if oldClass is the same as newClass but newClass is in a
1470 // namespace (and oldClass was not in a namespace).
1471
1472 if (oldClass == 0 || newClass == 0) return kFALSE;
1473
1474 UInt_t newlen = strlen(newClass->GetName());
1475 UInt_t oldlen = strlen(oldClass->GetName());
1476
1477 const char *oldname = oldClass->GetName();
1478 for (UInt_t i = oldlen, done = false, nest = 0; (i>0) && !done ; --i) {
1479 switch (oldClass->GetName()[i-1]) {
1480 case '>' : ++nest; break;
1481 case '<' : if (nest==0) return kFALSE; // the name is not well formed, give up.
1482 --nest; break;
1483 case ':' : if (nest == 0) oldname= &(oldClass->GetName()[i]); done = kTRUE; break;
1484 }
1485 }
1487 if (!(strlen(newClass->GetName()) > strlen(oldClass->GetName()))) {
1488 return kFALSE;
1489 }
1490
1491 const char* newEnd = & (newClass->GetName()[newlen-oldlen]);
1492
1493 if (0 != strcmp(newEnd, oldname)) {
1494 return kFALSE;
1495 }
1496
1497 Int_t oldv = oldClass->GetStreamerInfo()->GetClassVersion();
1498
1499 if (newClass->GetStreamerInfos() && oldv < newClass->GetStreamerInfos()->GetSize() && newClass->GetStreamerInfos()->At(oldv) && strcmp(newClass->GetStreamerInfos()->At(oldv)->GetName(), oldClass->GetName()) != 0) {
1500 // The new class has already a TStreamerInfo for the same version as
1501 // the old class and this was not the result of an import. So we do not
1502 // have a match
1503 return kFALSE;
1504 }
1505 return kTRUE;
1506 }
1507
1508////////////////////////////////////////////////////////////////////////////////
1509/// Import the streamerInfo from oldClass to newClass.
1510///
1511/// In case of conflict, returns the version number of the StreamerInfo
1512/// with the conflict.
1513/// Return 0 in case of success
1515
1516 TIter next(oldClass->GetStreamerInfos());
1518 while ((info = (TStreamerInfo*)next())) {
1519 info = (TStreamerInfo*)info->Clone();
1520 if (!info) {
1521 Error("ImportStreamerInfo","Unable to clone the StreamerInfo for %s.",(*next)->GetName());
1522 } else {
1523 info->SetClass(newClass);
1524 Int_t oldv = info->GetClassVersion();
1525 if (oldv > newClass->GetStreamerInfos()->GetSize() || newClass->GetStreamerInfos()->At(oldv) == 0) {
1526 // All is good.
1527 newClass->RegisterStreamerInfo(info);
1528 } else {
1529 // We verify that we are consistent and that
1530 // newcl->GetStreamerInfos()->UncheckedAt(info->GetClassVersion)
1531 // is already the same as info.
1532 if (strcmp(newClass->GetStreamerInfos()->At(oldv)->GetName(),
1533 oldClass->GetName()) != 0) {
1534 // The existing StreamerInfo does not already come from OldClass.
1535 // This is a real problem!
1536 return oldv;
1537 }
1538 }
1539 }
1540 }
1541 return 0;
1542 }
1543
1545 {
1546 // Return true if newClass is a likely valid conversion from
1547 // a TClonesArray
1548
1549 return newClass->GetCollectionProxy()
1550 && newClass->GetCollectionProxy()->GetValueClass()
1551 && !newClass->GetCollectionProxy()->HasPointers();
1552 }
1553
1555 {
1556 // Return true if oldClass and newClass points to 2 compatible collection.
1557 // i.e. they contains the exact same type.
1558
1559 TVirtualCollectionProxy *oldProxy = oldClass->GetCollectionProxy();
1560 TVirtualCollectionProxy *newProxy = newClass->GetCollectionProxy();
1561
1562 TClass *oldContent = oldProxy->GetValueClass();
1563 TClass *newContent = newProxy->GetValueClass();
1564
1566 if (oldContent) {
1567 if (oldContent == newContent) {
1569 } else if (newContent) {
1574 }
1575 } else {
1577 }
1578 } else {
1579 contentMatch = (newContent==0);
1580 }
1581
1582 if (contentMatch) {
1583 if ((oldContent==0 && oldProxy->GetType() == newProxy->GetType())
1584 ||(oldContent && oldProxy->HasPointers() == newProxy->HasPointers())) {
1585 // We have compatibles collections (they have the same content)!
1586 return kTRUE;
1587 }
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() == kFloat_t || oldProxy->GetType() == kFloat16_t)
1602 && (newProxy->GetType() == kFloat_t || newProxy->GetType() == kFloat16_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() == kDouble_t || oldProxy->GetType() == kDouble32_t)
1619 && (newProxy->GetType() == kDouble_t || newProxy->GetType() == kDouble32_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() == kLong_t || oldProxy->GetType() == kLong64_t)
1636 && (newProxy->GetType() == kLong_t || newProxy->GetType() == kLong64_t )) {
1637 // We have compatibles collections (they have the same content)!
1638 return (oldClass->GetCollectionType() == newClass->GetCollectionType());
1639 }
1640 return kFALSE;
1641 }
1642
1644 {
1645 // Return true if oldClass and newClass points to 2 compatible collection.
1646 // i.e. they contains the exact same type.
1647
1648 TVirtualCollectionProxy *oldProxy = oldClass->GetCollectionProxy();
1649 TVirtualCollectionProxy *newProxy = newClass->GetCollectionProxy();
1650
1651 if (oldProxy->GetValueClass() == 0 && newProxy->GetValueClass() == 0
1652 && (oldProxy->GetType() == kULong_t || oldProxy->GetType() == kULong64_t)
1653 && (newProxy->GetType() == kULong_t || newProxy->GetType() == kULong64_t )) {
1654 // We have compatibles collections (they have the same content)!
1655 return (oldClass->GetCollectionType() == newClass->GetCollectionType());
1656 }
1657 return kFALSE;
1658 }
1659
1660 TClass *FindAlternate(TClass *context, const std::string &i_name, std::string& newName)
1661 {
1662 // Return a class whose has the name as oldClass and can be found
1663 // within the scope of the class 'context'.
1664
1665 // First strip any 'const ' prefix or trailing '*'.
1666 std::string name(i_name);
1667 newName.clear();
1668 if (name.compare(0,6,"const ")==0) {
1669 newName = "const ";
1670 name.erase(0,6);
1671 }
1672 std::string suffix;
1673 UInt_t nstars = 0;
1674 while(name[name.length()-nstars-1]=='*') {
1675 ++nstars;
1676 suffix.append("*");
1677 }
1678 if (nstars) {
1679 name.erase(name.length()-nstars,nstars);
1680 }
1681
1682 std::string alternate(context->GetName());
1683 alternate.append("::");
1684 alternate.append(name);
1685
1686 TClass *altcl = TClass::GetClass(alternate.c_str(),/*load=*/ false,true);
1687 if (altcl) {
1688 newName.append(altcl->GetName());
1689 newName.append(suffix);
1690 return altcl;
1691 }
1692
1693 size_t ctxt_cursor = strlen(context->GetName());
1694 for (size_t level = 0; ctxt_cursor != 0; --ctxt_cursor) {
1695 switch (context->GetName()[ctxt_cursor]) {
1696 case '<': --level; break;
1697 case '>': ++level; break;
1698 case ':': if (level == 0) {
1699 // we encountered a scope not within a template
1700 // parameter.
1701 alternate.clear();
1702 alternate.append(context->GetName(),ctxt_cursor+1);
1703 alternate.append(name);
1704 altcl = TClass::GetClass(alternate.c_str(),/*load=*/ false,true);
1705 if (altcl) {
1706 newName.append(altcl->GetName());
1707 newName.append(suffix);
1708 return altcl;
1709 }
1710 }
1711 }
1712 }
1713 newName.clear();
1714 return 0;
1715 }
1716
1718 {
1719 assert(oldClass->GetCollectionProxy() && newClass->GetCollectionProxy());
1720
1721 TVirtualCollectionProxy *old = oldClass->GetCollectionProxy();
1722 TVirtualCollectionProxy *current = newClass->GetCollectionProxy();
1724
1726
1727 if (current->GetValueClass() == nullptr) {
1728 // This should really never happen (the content of map should always
1729 // be a pair and thus have a TClass ... so let's just give up ...
1730 // It actually happens in the case where one of the member is an
1731 // enum that is part of dictionary payload that is not yet
1732 // auto-loaded.
1733 return nullptr;
1734 }
1735 TVirtualStreamerInfo *info = current->GetValueClass()->GetStreamerInfo();
1736 if (info->GetElements()->GetEntriesFast() != 2) {
1737 return oldClass;
1738 }
1739 TStreamerElement *f = (TStreamerElement*) info->GetElements()->At(0);
1740 TStreamerElement *s = (TStreamerElement*) info->GetElements()->At(1);
1741
1742 // Since we do not create TClass for pair of unknown types, old->GetValueClass can
1743 // be nullptr even-though the type used be known. An example of such change
1744 // is `RooExpensiveObjectCache::ExpensiveObject` which used to be recorded
1745 // as `ExpensiveObject` in the name of the map ... making it unknown
1746 // (and this is precisely the type of change we are trying to handle here/below!)
1747 info = old->GetValueClass() ? old->GetValueClass()->GetStreamerInfo() : nullptr;
1748 assert(!info || info->GetElements()->GetEntriesFast() == 2);
1749 TStreamerElement *of = info ? (TStreamerElement*) info->GetElements()->At(0) : nullptr;
1750 TStreamerElement *os = info ? (TStreamerElement*) info->GetElements()->At(1) : nullptr;
1751
1752 TClass *firstNewCl = f ? f->GetClass() : 0;
1753 TClass *secondNewCl = s ? s->GetClass() : 0;
1754
1755 TClass *firstOldCl = of ? of->GetClass() : 0;
1756 TClass *secondOldCl = os ? os->GetClass() : 0;
1757
1758 if ((firstNewCl && !firstOldCl) || (secondNewCl && !secondOldCl))
1759 {
1760 std::vector<std::string> inside;
1761 int nestedLoc;
1763
1766 std::string firstNewName;
1767 std::string secondNewName;
1768 if (!info && !firstOldCl) {
1769 firstOldCl = TClass::GetClass(inside[1].c_str(), kTRUE, kTRUE);
1770 }
1771 if (!info && !secondOldCl) {
1772 secondOldCl = TClass::GetClass(inside[2].c_str(), kTRUE, kTRUE);
1773 }
1774 if (firstNewCl && !firstOldCl) {
1775 firstAltCl = FindAlternate(context, inside[1], firstNewName);
1776 } else if (firstAltCl) {
1777 firstNewName = firstAltCl->GetName();
1778 } else {
1779 firstNewName = inside[1];
1780 }
1781 if (secondNewCl && !secondOldCl) {
1782 secondAltCl = FindAlternate(context, inside[2], secondNewName);
1783 } else if (secondAltCl) {
1784 secondNewName = secondAltCl->GetName();
1785 } else {
1786 secondNewName = inside[2];
1787 }
1788 if ((firstNewCl && firstAltCl != firstOldCl) ||
1790
1791 // Need to produce new name.
1792 std::string alternate = inside[0];
1793 alternate.append("<");
1794 alternate.append(firstNewName);
1795 alternate.append(",");
1796 alternate.append(secondNewName);
1797 // We are intentionally dropping any further arguments,
1798 // they would be using the wrong typename and would also be
1799 // somewhat superflous since this is for the old layout.
1800 if (alternate[alternate.length()-1]=='>') {
1801 alternate.append(" ");
1802 }
1803 alternate.append(">");
1804 return TClass::GetClass(alternate.c_str(),true,true);
1805 }
1806 }
1807
1808 } else if (current->GetValueClass() && !old->GetValueClass()
1809 && old->GetType() == kInt_t) {
1810
1811 // The old CollectionProxy claims it contains int (or enums) while
1812 // the new one claims to contain a class. It is likely that we have
1813 // in the collection name a class (typedef) name that is missing its
1814 // scope. Let's try to check.
1815
1816 std::vector<std::string> inside;
1817 int nestedLoc;
1819
1820 // Now let's if we can find this missing type.
1821 std::string newName;
1822 TClass *altcl = FindAlternate(context, inside[1], newName);
1823
1824 if (altcl) {
1825 std::string alternate = inside[0];
1826 alternate.append("<");
1827 alternate.append(newName);
1828 // We are intentionally dropping any further arguments,
1829 // they would be using the wrong typename and would also be
1830 // somewhat superflous since this is for the old layout.
1831 if (alternate[alternate.length()-1]=='>') {
1832 alternate.append(" ");
1833 }
1834 alternate.append(">");
1835 return TClass::GetClass(alternate.c_str(),true,true);
1836 }
1837 }
1838 return 0;
1839 }
1840
1841 // Makes sure kBuildOldUsed set once BuildOld finishes
1842 struct TBuildOldGuard {
1843 TBuildOldGuard(TStreamerInfo* info): fInfo(info) {
1844 fInfo->SetBit(TStreamerInfo::kBuildRunning);
1845 }
1846 ~TBuildOldGuard() {
1847 fInfo->ResetBit(TStreamerInfo::kBuildRunning);
1848 fInfo->SetBit(TStreamerInfo::kBuildOldUsed);
1849 }
1850 TStreamerInfo* fInfo;
1851 };
1852}
1853
1854////////////////////////////////////////////////////////////////////////////////
1855/// rebuild the TStreamerInfo structure
1856
1858{
1860
1861 if ( TestBit(kBuildOldUsed) ) return;
1862
1863 // Are we recursing on ourself?
1865
1866 // This is used to avoid unwanted recursive call to Build and make sure
1867 // that we record the execution of BuildOld.
1868 TBuildOldGuard buildOldGuard(this);
1869
1870 if (gDebug > 0) {
1871 printf("\n====>Rebuilding TStreamerInfo for class: %s, version: %d\n", GetName(), fClassVersion);
1872 }
1873
1875
1878 {
1879 // Handle emulated classes and STL containers specially.
1880 // in this case BuildRealData would call BuildOld for this same
1881 // TStreamerInfo to be able to build the real data on it.
1882 } else {
1884 }
1885 }
1886 else {
1887 // This is to support the following case
1888 // Shared library: Event v2
1889 // calling cl->GetStreamerInfo(1)->BuildOld(); (or equivalent)
1890 // which calls cl->BuildReadData()
1891 // which set fRealData to some value
1892 // then call Event()
1893 // which call cl->GetStreamerInfo()
1894 // which call cl->BuildRealData();
1895 // which returns immediately (upon seeing fRealData!=0)
1896 // then the main StreamerInfo build using the partial content of fRealData
1897 // then BuildRealData returns
1898 // then GetStreamerInfo() returns
1899 // then Event() returns
1900 // then fRealData is finished being populated
1901 // then this function continue,
1902 // then it uses the main streamerInfo
1903 // .... which is incomplete.
1904 //
1905 // Instead we force the creation of the main streamerInfo object
1906 // before the creation of fRealData.
1908 }
1909
1910 TIter next(fElements);
1912 Int_t offset = 0;
1914
1915 constexpr size_t kSizeOfPtr = sizeof(void*);
1916
1917 int nBaze = 0;
1918
1919 if ((fElements->GetEntriesFast() == 1) && !strcmp(fElements->At(0)->GetName(), "This")) {
1920 if (fClass->GetCollectionProxy()) {
1921 element = (TStreamerElement*)next();
1922 element->SetNewType( element->GetType() );
1923 element->SetNewClass( fClass );
1924 } else if (((TStreamerElement*)fElements->At(0))->GetType() == TStreamerInfo::kSTL &&
1925 strcmp( ((TStreamerElement*)fElements->At(0))->GetTypeName(),GetName()) != 0) {
1926 // We have a collection that was proxied but does not have a collection proxy,
1927 // let's put one in place just for fun ... humm however we have no clue what is the value
1928 // type ....
1929
1930 // For now wild guess ....
1931
1932 }
1933 }
1934
1935 TClass *allocClass = 0;
1937
1938 //---------------------------------------------------------------------------
1939 // Get schema rules for this class
1940 /////////////////////////////////////////////////////////////////////////////
1941
1942 ROOT::TSchemaRuleSet::TMatches rules;
1944
1945 if (ruleSet) rules = ruleSet->FindRules( GetName(), fOnFileClassVersion, fCheckSum );
1946
1949 fNVirtualInfoLoc = 0;
1950 delete [] fVirtualInfoLoc;
1951 fVirtualInfoLoc = 0;
1952
1953 while ((element = (TStreamerElement*) next())) {
1955 || element->TestBit(TStreamerElement::kCache) )
1956 {
1957 // Prevent BuildOld from modifying existing ArtificialElement (We need to review when and why BuildOld
1958 // needs to be re-run; it might be needed if the 'current' class change (for example from being an onfile
1959 // version to being a version loaded from a shared library) and we thus may have to remove the artificial
1960 // element at the beginning of BuildOld)
1961
1962 continue;
1963 };
1964
1965 element->SetNewType(element->GetType());
1966 if (element->IsBase()) {
1967 //---------------------------------------------------------------------
1968 // Dealing with nonSTL bases
1969 ///////////////////////////////////////////////////////////////////////
1970
1971 if (element->IsA() == TStreamerBase::Class()) {
1973#if defined(PROPER_IMPLEMEMANTION_OF_BASE_CLASS_RENAMING)
1975#else
1976 // Currently the base class renaming does not work, so we use the old
1977 // version of the code which essentially disable the next if(!baseclass ..
1978 // statement.
1979 // During the TStreamerElement's Init an emulated TClass might be replaced
1980 // by one from the dictionary, we use a TClassRef to be informed of the change.
1982#endif
1983
1984 //------------------------------------------------------------------
1985 // We do not have this base class - check if we're renaming
1986 ////////////////////////////////////////////////////////////////////
1987
1989 const ROOT::TSchemaRule* rule = (rules ? rules.GetRuleWithSource( base->GetName() ) : 0);
1990
1991 //---------------------------------------------------------------
1992 // No renaming, sorry
1993 /////////////////////////////////////////////////////////////////
1994
1995 if( !rule ) {
1996 Error("BuildOld", "Could not find base class: %s for %s and could not find any matching rename rule\n", base->GetName(), GetName());
1997 continue;
1998 }
1999
2000 //----------------------------------------------------------------
2001 // Find a new target class
2002 /////////////////////////////////////////////////////////////////
2003
2004 const TObjArray* targets = rule->GetTarget();
2005 if( !targets ) {
2006 Error("BuildOld", "Could not find base class: %s for %s, renaming rule was found but is malformed\n", base->GetName(), GetName());
2007 }
2008 TString newBaseClass = ((TObjString*)targets->At(0))->GetString();
2010 base->SetNewBaseClass( baseclass );
2011 }
2012 //-------------------------------------------------------------------
2013 // No base class in emulated mode
2014 ////////////////////////////////////////////////////////////////////
2015
2016 else if( !baseclass ) {
2017 baseclass = base->GetClassPointer();
2018 if (!baseclass) {
2019 Warning("BuildOld", "Missing base class: %s skipped", base->GetName());
2020 // FIXME: Why is the version number 1 here? Answer: because we don't know any better at this point
2021 baseclass = new TClass(element->GetName(), 1, 0, 0, -1, -1);
2022 element->Update(0, baseclass);
2023 }
2024 }
2025 baseclass->BuildRealData();
2026
2027 // Calculate the offset using the 'real' base class name (as opposed to the
2028 // '@@emulated' in the case of the emulation of an abstract base class.
2030
2031 // Deal with potential schema evolution (renaming) of the base class.
2032 if (baseOffset < 0) {
2033
2034 // See if this base element can be converted into one of
2035 // the existing base class.
2037 if (listOfBases) {
2038 TBaseClass* bc = 0;
2040 while ((bc = (TBaseClass*) nextBC())) {
2041 TClass *in_memory_bcl = bc->GetClassPointer();
2042 if (in_memory_bcl && in_memory_bcl->GetSchemaRules()) {
2043 auto baserule = in_memory_bcl->GetSchemaRules()->FindRules( base->GetName(), base->GetBaseVersion(), base->GetBaseCheckSum() );
2044 if (!baserule.empty()) {
2046 baseOffset = bc->GetDelta();
2047
2048 }
2049 }
2050 }
2051 }
2052 }
2053 // We need to initialize the element now, as we need the
2054 // correct StreamerInfo next.
2055 element->Init(this);
2056
2057 // Force the StreamerInfo "Compilation" of the base classes first. This is necessary in
2058 // case the base class contains a member used as an array dimension in the derived classes.
2060 if (fClass->GetState() == TClass::kEmulated && (baseclass->Property() & kIsAbstract)) {
2061 Int_t version = base->GetBaseVersion();
2062 if (version >= 0 || base->GetBaseCheckSum() == 0) {
2063 infobase = (TStreamerInfo*)baseclass->GetStreamerInfoAbstractEmulated(version);
2064 } else {
2065 infobase = (TStreamerInfo*)baseclass->FindStreamerInfoAbstractEmulated(base->GetBaseCheckSum());
2066 }
2067 if (infobase) baseclass = infobase->GetClass();
2068 }
2069 else {
2071 }
2072
2073 if (infobase && infobase->fComp == 0) {
2074 infobase->BuildOld();
2075 }
2076
2077 if (infobase && shouldHaveInfoLoc && baseclass->GetState() == TClass::kEmulated ) {
2078 if ( (fNVirtualInfoLoc + infobase->fNVirtualInfoLoc) > virtualInfoLocAlloc ) {
2079 ULong_t *store = fVirtualInfoLoc;
2080 virtualInfoLocAlloc = 16 * ( (fNVirtualInfoLoc + infobase->fNVirtualInfoLoc) / 16 + 1);
2082 if (store) {
2084 delete [] store;
2085 }
2086 }
2087 for (int nloc = 0; nloc < infobase->fNVirtualInfoLoc; ++nloc) {
2088 fVirtualInfoLoc[ fNVirtualInfoLoc + nloc ] = baseOffset + infobase->fVirtualInfoLoc[nloc];
2089 }
2090 fNVirtualInfoLoc += infobase->fNVirtualInfoLoc;
2091 }
2092
2093
2094 {
2095 if (baseOffset < 0) {
2097 }
2098 }
2099 element->SetOffset(baseOffset);
2100 offset += baseclass->Size();
2101
2102 continue;
2103 } else {
2104 // Not a base elem but still base, string or STL as a base
2105 nBaze++;
2107 Int_t baseOffset = -1;
2108 Int_t asize = 0;
2109 if (listOfBases) {
2110 // Do a search for the classname and some of its alternatives spelling.
2111
2112 TBaseClass* bc = 0;
2114 while ((bc = (TBaseClass*) nextBC())) {
2115 if (strchr(bc->GetName(), '<') || !strcmp(bc->GetName(),"string")) {
2118 if (bcName == elName) {
2119 break;
2120 }
2121 }
2122 }
2123
2124 if (!bc) {
2125 // Error("BuildOld", "Could not find STL base class: %s for %s\n", element->GetName(), GetName());
2126 offset = kMissing;
2127 element->SetOffset(kMissing);
2129 continue;
2130 } else if (bc->GetClassPointer()->GetCollectionProxy()
2131 && !bc->GetClassPointer()->IsLoaded()
2132 && bc->GetClassPointer()->GetCollectionProxy()->GetCollectionType() != ROOT::kSTLvector) {
2133 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());
2134 offset = kMissing;
2135 element->SetOffset(kMissing);
2137 continue;
2138 }
2139 baseOffset = bc->GetDelta();
2140 asize = bc->GetClassPointer()->Size();
2141
2142 } else if (fClass->GetState() == TClass::kEmulated) {
2143 // Do a search for the classname and some of its alternatives spelling.
2144
2146 if (newInfo == this) {
2148 asize = element->GetSize();
2149 } else if (newInfo) {
2150 TIter newElems( newInfo->GetElements() );
2152 while( (newElement = (TStreamerElement*)newElems()) ) {
2153 const char *newElName = newElement->GetName();
2154 if (newElement->IsBase() && (strchr(newElName,'<') || !strcmp(newElName,"string")) ) {
2157 if (bcName == elName) {
2158 break;
2159 }
2160 }
2161 }
2162 if (!newElement) {
2163 Error("BuildOld", "Could not find STL base class: %s for %s\n", element->GetName(), GetName());
2164 continue;
2165 }
2166 baseOffset = newElement->GetOffset();
2167 asize = newElement->GetSize();
2168 }
2169 }
2170 if (baseOffset == -1) {
2171 TClass* cb = element->GetClassPointer();
2172 if (!cb) {
2174 continue;
2175 }
2176 asize = cb->Size();
2178 }
2179
2180 // we know how to read but do we know where to read?
2181 if (baseOffset < 0) {
2183 continue;
2184 }
2185 element->SetOffset(baseOffset);
2186 offset += asize;
2187 element->Init(this);
2188 continue;
2189 } // if element is of type TStreamerBase or not.
2190 } // if (element->IsBase())
2191
2192 // If we get here, this means that we looked at all the base classes.
2194 fNVirtualInfoLoc = 1;
2195 fVirtualInfoLoc = new ULong_t[1]; // To allow for a single delete statement.
2197 offset += sizeof(TStreamerInfo*);
2198 }
2199
2200 TDataMember* dm = 0;
2201
2202 std::string typeNameBuf; // Keep underlying buffer alive until actually used.
2203 const char* dmType = nullptr;
2204 Bool_t dmIsPtr = false;
2205 TDataType* dt(nullptr);
2206 Int_t ndim = 0 ; //dm->GetArrayDim();
2207 std::array<Int_t, 5> maxIndices; // 5 is the maximum supported in TStreamerElement::SetMaxIndex
2209
2210 // First set the offset and sizes.
2212 // Note the initilization in this case are
2213 // delayed until __after__ the schema evolution
2214 // section, just in case the info has changed.
2215
2216 // We are in the emulated case
2217 streamer = 0;
2218 element->Init(this);
2219 } else {
2220 // The class is known to Cling (and thus is not emulated)
2221 // and we need to use the real offsets.
2222 // However we may not have a 'proper' TClass for it
2223 // (in which case IsLoaded will be false and GetImplFileLine will be -1)
2224
2225 // First look for the data member in the current class
2227 if (dm && dm->IsPersistent()) {
2229 streamer = 0;
2231 element->SetOffset(offset);
2232 element->Init(this);
2233
2234 // Treat unique pointers and std arrays
2235 dmType = dm->GetTypeName();
2236 dmIsPtr = dm->IsaPointer();
2239 if (nameChanged) {
2240 if (typeNameBuf.back() == '*') {
2241 dmIsPtr = true;
2242 typeNameBuf.pop_back();
2243 while(typeNameBuf.back() == '*') typeNameBuf.pop_back();
2244 }
2245 dmType = typeNameBuf.c_str();
2246 }
2247 if ((isStdArray = TClassEdit::IsStdArray(dmType))){ // We tackle the std array case
2250 maxIndices,
2251 ndim);
2252 dmType = typeNameBuf.c_str();
2253 dt = gROOT->GetType(dmType);
2254 }
2255
2256 // We have a loaded class, let's make sure that if we have a collection
2257 // it is also loaded.
2260 if (dmClassName.Index("const ")==0) dmClassName.Remove(0,6);
2261 TClass *elemDm = ! (dt || dm->IsBasic()) ? TClass::GetClass(dmClassName.Data()) : 0;
2262 if (elemDm && elemDm->GetCollectionProxy()
2263 && !elemDm->IsLoaded()
2264 && elemDm->GetCollectionProxy()->GetCollectionType() != ROOT::kSTLvector) {
2265 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());
2266 offset = kMissing;
2267 element->SetOffset(kMissing);
2269 }
2270 element->SetStreamer(streamer);
2271 int narr = element->GetArrayLength();
2272 if (!narr) {
2273 narr = 1;
2274 }
2275 int dsize = dm->GetUnitSize();
2276 element->SetSize(dsize*narr);
2277 } else {
2278 // We did not find it, let's look for it in the base classes via TRealData
2279 TRealData* rd = fClass->GetRealData(element->GetName());
2280 if (rd && rd->GetDataMember()) {
2281 element->SetOffset(rd->GetThisOffset());
2282 element->Init(this);
2283 dm = rd->GetDataMember();
2284 dmType = dm->GetTypeName();
2285 dmIsPtr = dm->IsaPointer();
2286 int narr = element->GetArrayLength();
2287 if (!narr) {
2288 narr = 1;
2289 }
2290 int dsize = dm->GetUnitSize();
2291 element->SetSize(dsize*narr);
2292 } else if (fClass->IsSyntheticPair()) {
2293 auto pattern = (TStreamerInfo*)fClass->GetStreamerInfos()->At(fClass->GetClassVersion());
2294 streamer = 0;
2295 element->Init(this);
2296 if (pattern && pattern != this && pattern->IsBuilt()) {
2298 pattern->GetStreamerElement(element->GetName(), pair_element_offset);
2300 element->SetOffset(pair_element_offset);
2301 }
2302 }
2303 } else if (strcmp(element->GetName(), "fData") == 0 && strncmp(GetName(), "ROOT::VecOps::RVec", 18) == 0) {
2304 Error("BuildCheck", "Reading RVecs that were written directly to file before ROOT v6.24 is not "
2305 "supported, the program will likely crash.");
2306 element->SetOffset(0);
2307 element->Init(this);
2308 dmType = element->GetTypeName();
2309 dmIsPtr = false;
2310 }
2311 }
2312 } // Class corresponding to StreamerInfo is emulated or not.
2313
2314 // Now let's deal with Schema evolution
2315 Int_t newType = -1;
2317
2318 if (dm && dm->IsPersistent()) {
2319 auto theType = isStdArray ? dt : dm->GetDataType();
2320 if (theType) {
2321 Bool_t isArray = isStdArray || element->GetArrayLength() >= 1;
2322 Bool_t hasCount = element->HasCounter();
2323 // data member is a basic type
2324 if ((fClass == TObject::Class()) && !strcmp(dm->GetName(), "fBits")) {
2325 //printf("found fBits, changing dtype from %d to 15\n", dtype);
2326 newType = kBits;
2327 } else {
2328 // All the values of EDataType have the same semantic in EReadWrite
2329 newType = (EReadWrite)theType->GetType();
2330 }
2331 if ((newType == ::kChar_t) && dmIsPtr && !isArray && !hasCount) {
2333 } else if (dmIsPtr) {
2334 newType += kOffsetP;
2335 } else if (isArray) {
2336 newType += kOffsetL;
2337 }
2338 }
2339 if (newType == -1) {
2341 }
2342 } else {
2343 // Either the class is not loaded or the data member is gone
2344 if (!fClass->IsLoaded()) {
2346 if (newInfo && (newInfo != this)) {
2347 TStreamerElement* newElems = (TStreamerElement*) newInfo->GetElements()->FindObject(element->GetName());
2348 newClass = newElems ? newElems->GetClassPointer() : 0;
2349 if (newClass == 0) {
2350 newType = newElems ? newElems->GetType() : -1;
2351 if (!(newType < kObject)) {
2352 // sanity check.
2353 newType = -1;
2354 }
2355 }
2356 } else {
2357 newClass = element->GetClassPointer();
2358 if (newClass.GetClass() == 0) {
2359 newType = element->GetType();
2360 if (!(newType < kObject)) {
2361 // sanity check.
2362 newType = -1;
2363 }
2364 }
2365 }
2366 }
2367 }
2368
2369 if (newType > 0) {
2370 // Case of a numerical type
2371 if (element->GetType() >= TStreamerInfo::kObject) {
2372 // Old type was not a numerical type.
2374 } else if (element->GetType() != newType) {
2375 element->SetNewType(newType);
2376 if (gDebug > 0) {
2377 // coverity[mixed_enums] - All the values of EDataType have the same semantic in EReadWrite
2378 Info("BuildOld", "element: %s %s::%s has new type: %s/%d", element->GetTypeName(), GetName(), element->GetName(), dm ? dm->GetFullTypeName() : TDataType::GetTypeName((EDataType)newType), newType);
2379 }
2380 }
2381 } else if (newClass.GetClass()) {
2382 // Sometime BuildOld is called again.
2383 // In that case we might already have fix up the streamer element.
2384 // So we need to go back to the original information!
2385 newClass.Reset();
2387 if (oldClass == newClass.GetClass()) {
2388 // Nothing to do, also in the unique_ptr case :)
2389 } else if (ClassWasMovedToNamespace(oldClass, newClass.GetClass())) {
2390 Int_t oldv;
2391 if (0 != (oldv = ImportStreamerInfo(oldClass, newClass.GetClass()))) {
2392 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);
2393 } else {
2394 element->SetTypeName(newClass->GetName());
2395 if (gDebug > 0) {
2396 Warning("BuildOld", "element: %s::%s %s has new type %s", GetName(), element->GetTypeName(), element->GetName(), newClass->GetName());
2397 }
2398 }
2399 } else if (oldClass == TClonesArray::Class()) {
2400 if (ContainerMatchTClonesArray(newClass.GetClass())) {
2401 Int_t elemType = element->GetType();
2403 element->Update(oldClass, newClass.GetClass());
2404 TVirtualCollectionProxy *cp = newClass->GetCollectionProxy();
2406 element->SetStreamer(ms);
2407
2408 // When the type is kObject, the TObject::Streamer is used instead
2409 // of the TStreamerElement's streamer. So let force the usage
2410 // of our streamer
2411 if (element->GetType() == kObject) {
2412 element->SetNewType(kAny);
2413 element->SetType(kAny);
2414 }
2415 if (gDebug > 0) {
2416 Warning("BuildOld","element: %s::%s %s has new type %s", GetName(), element->GetTypeName(), element->GetName(), newClass->GetName());
2417 }
2418 } else {
2420 }
2421 } else if (oldClass && oldClass->GetCollectionProxy() && newClass->GetCollectionProxy()) {
2422 {
2427 }
2428 }
2430 Int_t oldkind = oldClass->GetCollectionType();
2431 Int_t newkind = newClass->GetCollectionType();
2432
2435
2436 Int_t elemType = element->GetType();
2438
2439 TClassStreamer *streamer2 = newClass->GetStreamer();
2440 if (streamer2) {
2442 if (ms && ms->IsValid()) {
2443 element->SetStreamer(ms);
2444 switch( element->GetType() ) {
2445 //case TStreamerInfo::kSTLvarp: // Variable size array of STL containers.
2446 case TStreamerInfo::kSTLp: // Pointer to container with no virtual table (stl) and no comment
2447 case TStreamerInfo::kSTLp + TStreamerInfo::kOffsetL: // array of pointers to container with no virtual table (stl) and no comment
2449 break;
2450 case TStreamerInfo::kSTL: // container with no virtual table (stl) and no comment
2451 case TStreamerInfo::kSTL + TStreamerInfo::kOffsetL: // array of containers with no virtual table (stl) and no comment
2452 break;
2453 }
2454 } else {
2455 delete ms;
2456 }
2457 }
2458 element->Update(oldClass, newClass.GetClass());
2459
2460 } else if ( (newkind==ROOT::kSTLmap || newkind==ROOT::kSTLmultimap) &&
2462 // This case was not previously not supported, however it is unclear
2463 // why so we keep it as a separate case for the time behind.
2464 element->Update(oldClass, newClass.GetClass());
2465 } else {
2466 element->Update(oldClass, newClass.GetClass());
2467 }
2468 // Is this needed ? : element->SetSTLtype(newelement->GetSTLtype());
2469 if (gDebug > 0) {
2470 Warning("BuildOld","element: %s::%s %s has new type %s", GetName(), element->GetTypeName(), element->GetName(), newClass->GetName());
2471 }
2473 // Actually nothing to do, since both are the same collection of double in memory.
2475 // Actually nothing to do, since both are the same collection of double in memory.
2477 // Not much to do since both are the same collection of 8 bits entities on file.
2478 element->Update(oldClass, newClass.GetClass());
2480 // Not much to do since both are the same collection of 8 bits unsigned entities on file
2481 element->Update(oldClass, newClass.GetClass());
2482 } else if (newClass->GetSchemaRules()->HasRuleWithSourceClass( oldClass->GetName() )) {
2483 //------------------------------------------------------------------------
2484 // We can convert one type to another (at least for some of the versions).
2485 /////////////////////////////////////////////////////////////////
2486
2487 element->SetNewClass( newClass );
2488 } else {
2490 }
2491
2492 } else if(oldClass &&
2493 newClass.GetClass() &&
2494 newClass->GetSchemaRules() &&
2495 newClass->GetSchemaRules()->HasRuleWithSourceClass( oldClass->GetName() ) ) {
2496 //------------------------------------------------------------------------
2497 // We can convert one type to another (at least for some of the versions).
2498 ////////////////////////////////////////////////////////////////////
2499
2500 element->SetNewClass( newClass );
2501 } else {
2503 }
2504 // Humm we still need to make sure we have the same 'type' (pointer, embedded object, array, etc..)
2507 if (dm) {
2508 if (dmIsPtr) {
2509 if (strncmp(dm->GetTitle(),"->",2)==0) {
2510 // We are fine, nothing to do.
2511 if (newClass->IsTObject()) {
2512 newType = kObjectp;
2513 } else if (newClass->GetCollectionProxy()) {
2514 newType = kSTLp;
2515 } else {
2516 newType = kAnyp;
2517 }
2518 } else {
2519 if (TClass::GetClass(dm->GetTypeName())->IsTObject()) {
2520 newType = kObjectP;
2521 } else if (newClass->GetCollectionProxy()) {
2522 newType = kSTLp;
2523 } else {
2524 newType = kAnyP;
2525 }
2526 }
2527 } else {
2528 if (newClass->GetCollectionProxy()) {
2529 newType = kSTL;
2530 } else if (newClass == TString::Class()) {
2531 newType = kTString;
2532 } else if (newClass == TObject::Class()) {
2533 newType = kTObject;
2534 } else if (newClass == TNamed::Class()) {
2535 newType = kTNamed;
2536 } else if (newClass->IsTObject()) {
2537 newType = kObject;
2538 } else {
2539 newType = kAny;
2540 }
2541 }
2542 if ((!dmIsPtr || newType==kSTLp) && (isStdArray ? ndim : dm->GetArrayDim()) > 0) {
2543 newType += kOffsetL;
2544 }
2545 } else if (!fClass->IsLoaded()) {
2547 if (newInfo && (newInfo != this)) {
2548 TStreamerElement* newElems = (TStreamerElement*) newInfo->GetElements()->FindObject(element->GetName());
2549 if (newElems) {
2550 newType = newElems->GetType();
2551 }
2552 } else {
2553 newType = element->GetType();
2554 }
2555 }
2556 if (element->GetType() == kSTL
2557 || ((element->GetType() == kObject || element->GetType() == kAny || element->GetType() == kObjectp || element->GetType() == kAnyp)
2559 {
2561
2562 } else if (element->GetType() == kSTLp || ((element->GetType() == kObjectP || element->GetType() == kAnyP) && oldClass == TClonesArray::Class()) )
2563 {
2565
2566 } else if (element->GetType() == kSTL + kOffsetL
2567 || ((element->GetType() == kObject + kOffsetL|| element->GetType() == kAny + kOffsetL|| element->GetType() == kObjectp+ kOffsetL || element->GetType() == kAnyp+ kOffsetL)
2569 {
2571
2572 } else if (element->GetType() == kSTLp + kOffsetL || ((element->GetType() == kObjectP+ kOffsetL || element->GetType() == kAnyP+ kOffsetL) && oldClass == TClonesArray::Class()) )
2573 {
2575
2576 } else if ((element->GetType() == kObjectp || element->GetType() == kAnyp
2577 || element->GetType() == kObject || element->GetType() == kAny
2578 || element->GetType() == kTObject || element->GetType() == kTNamed || element->GetType() == kTString )) {
2579 // We had Type* ... ; //-> or Type ...;
2580 // this is completely compatible with the same and with a embedded object.
2581 if (newType != -1) {
2582 if (newType == kObjectp || newType == kAnyp
2583 || newType == kObject || newType == kAny
2584 || newType == kTObject || newType == kTNamed || newType == kTString) {
2585 // We are fine, no transformation to make
2586 element->SetNewType(newType);
2587 } else {
2588 // We do not support this yet.
2590 }
2591 } else {
2592 // We have no clue
2593 printf("%s We have no clue\n", dm->GetName());
2595 }
2596 } else if (element->GetType() == kObjectP || element->GetType() == kAnyP) {
2597 if (newType != -1) {
2598 if (newType == kObjectP || newType == kAnyP ) {
2599 // nothing to do}
2600 } else {
2602 }
2603 } else {
2604 // We have no clue
2606 }
2607 }
2608 }
2609 if (cannotConvert) {
2611 if (gDebug > 0) {
2612 // coverity[mixed_enums] - All the values of EDataType have the same semantic in EReadWrite
2613 Info("BuildOld", "element: %s %s::%s has new type: %s/%d", element->GetTypeName(), GetName(), element->GetName(), dm ? dm->GetFullTypeName() : TDataType::GetTypeName((EDataType)newType), newType);
2614 }
2615 }
2616 } else {
2618 offset = kMissing;
2619 element->SetOffset(kMissing);
2620 }
2621
2623 // Note the initialization in this case are
2624 // delayed until __after__ the schema evolution
2625 // section, just in case the info has changed.
2626
2627 // The class is NOT known to Cling, i.e. is emulated,
2628 // and we need to use the calculated offset.
2629
2630 Int_t asize;
2631 if (element->GetType() == TStreamerInfo::kSTL &&
2632 strcmp(element->GetName(),"This") == 0 &&
2633 strcmp(element->GetTypeName(),GetName()) == 0 &&
2635 // Humm .. we are missing the collection Proxy
2636 // for a proxied (custom) collection ... avoid
2637 // an infinite recursion and take a wild guess
2638 asize = sizeof(std::vector<int>);
2639 } else {
2640 // Regular case
2641 asize = element->GetSize();
2642 }
2643 // align the non-basic data types (required on alpha and IRIX!!)
2644 if ((offset % kSizeOfPtr) != 0) {
2646 }
2647 element->SetOffset(offset);
2648 offset += asize;
2649 }
2650
2651 if (!wasCompiled && rules) {
2652 if (rules.HasRuleWithSource( element->GetName(), kTRUE ) ) {
2653
2654 if (allocClass == 0) {
2656 if (!infoalloc) {
2657 Error("BuildOld","Unable to create the StreamerInfo for %s.",TString::Format("%s@@%d",GetName(),GetOnFileClassVersion()).Data());
2658 } else {
2659 // Need to find the source of rules where an implicit conversion is requested.
2660 if (rules) {
2661 TIter alloc_next(infoalloc->fElements);
2663 while ((alloc_element = (TStreamerElement *)alloc_next())) {
2664 if (rules.HasRuleWithSource(alloc_element->GetName(), kTRUE)) {
2665 auto r = rules.GetRuleWithSource(alloc_element->GetName());
2666 assert(r && r->GetSource());
2667 auto s =
2668 (ROOT::TSchemaRule::TSources *)(r->GetSource()->FindObject(alloc_element->GetName()));
2669 assert(s);
2670 UpdateFromRule(this, s, alloc_element);
2671 }
2672 }
2673 }
2674 infoalloc->SetBit(kBuildOldUsed,false);
2675 infoalloc->BuildCheck();
2676 infoalloc->BuildOld();
2677 allocClass = infoalloc->GetClass();
2678 }
2679 }
2680
2681 // Now that we are caching the unconverted element, we do not assign it to the real type even if we could have!
2682 if (element->GetNewType()>0 /* intentionally not including base class for now */
2683 && !rules.HasRuleWithTarget( element->GetName(), kTRUE ) ) {
2684
2685 TStreamerElement *copy = (TStreamerElement*)element->Clone();
2687 next(); // move the cursor passed the insert object.
2689 element = copy;
2690
2691 // 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() );
2692 } else {
2693 // If the element is just cached and not repeat, we need to inject an element
2694 // to insure the writing.
2697 next(); // move the cursor passed the insert object.
2699 writecopy->SetNewType( writecopy->GetType() );
2700 writecopy->SetOffset(element->GetOffset());
2701 }
2703
2704 // Get one of the potentially many rules applicable
2705 // We should check that we don't have a second rule
2706 auto r = rules.GetRuleWithSource(element->GetName());
2707 assert(r && r->GetSource());
2708 auto s = (ROOT::TSchemaRule::TSources *)(r->GetSource()->FindObject(element->GetName()));
2709 assert(s);
2710
2711 UpdateFromRule(this, s, element);
2712
2713 element->SetOffset(infoalloc ? infoalloc->GetOffset(element->GetName()) : 0);
2714 } else if (rules.HasRuleWithTarget( element->GetName(), kTRUE ) ) {
2715 // The data member exist in the onfile StreamerInfo and there is a rule
2716 // that has the same member 'only' has a target ... so this means we are
2717 // asked to ignore the input data ...
2718 if (element->GetType() == kCounter) {
2719 // If the element is a counter, we will need its value to read
2720 // other data member, so let's do so (by not disabling it) even
2721 // if the value will be over-written by a rule.
2722 } else {
2723 element->SetOffset(kMissing);
2724 }
2725 }
2726 } else if (rules && rules.HasRuleWithTarget( element->GetName(), kTRUE ) ) {
2727 // The data member exist in the onfile StreamerInfo and there is a rule
2728 // that has the same member 'only' has a target ... so this means we are
2729 // asked to ignore the input data ...
2730 if (element->GetType() == kCounter) {
2731 // If the element is a counter, we will need its value to read
2732 // other data member, so let's do so (by not disabling it) even
2733 // if the value will be over-written by a rule.
2734 } else {
2735 element->SetOffset(kMissing);
2736 }
2737 }
2738
2740 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") );
2741 }
2742 }
2743
2744 // If we get here, this means that there no data member after the last base class
2745 // (or no base class at all).
2747 fNVirtualInfoLoc = 1;
2748 fVirtualInfoLoc = new ULong_t[1]; // To allow for a single delete statement.
2750 offset += sizeof(TStreamerInfo*);
2751 }
2752
2753 // change order , move "bazes" to the end. Workaround old bug
2754 if ((fOldVersion <= 2) && nBaze) {
2758 int narr = arr.GetLast() + 1;
2759 int iel;
2760 int jel = 0;
2761 int kel = 0;
2762 for (iel = 0; iel < narr; ++iel) {
2764 if (element->IsBase() && (element->IsA() != TStreamerBase::Class())) {
2765 tai[kel++] = element;
2766 } else {
2767 arr[jel++] = element;
2768 }
2769 }
2770 for (kel = 0; jel < narr;) {
2771 arr[jel++] = tai[kel++];
2772 }
2773 }
2774
2775 // Now add artificial TStreamerElement (i.e. rules that creates new members or set transient members).
2777
2778 if (!wasCompiled && allocClass) {
2779
2780 TStreamerElement *el = new TStreamerArtificial("@@alloc","", 0, TStreamerInfo::kCacheNew, allocClass->GetName());
2782
2783 el = new TStreamerArtificial("@@dealloc","", 0, TStreamerInfo::kCacheDelete, allocClass->GetName());
2784 fElements->Add( el );
2785 }
2786
2787 Compile();
2788}
2789
2790////////////////////////////////////////////////////////////////////////////////
2791/// If opt contains 'built', reset this StreamerInfo as if Build or BuildOld
2792/// was never called on it (useful to force their re-running).
2793
2795{
2796 TString opt = option;
2797 opt.ToLower();
2798
2799 if (opt.Contains("build")) {
2801
2802 delete [] fComp; fComp = 0;
2803 delete [] fCompFull; fCompFull= 0;
2804 delete [] fCompOpt; fCompOpt = 0;
2805
2806 fNdata = 0;
2807 fNfulldata = 0;
2808 fNslots= 0;
2809 fSize = 0;
2810
2813
2814 TIter next(fElements);
2815 while (auto element = (TStreamerElement*)next()) {
2816 element->SetOffset(0);
2817 }
2818
2822 if (fReadText) fReadText->fActions.clear();
2826 if (fWriteText) fWriteText->fActions.clear();
2827 }
2828}
2829
2830namespace {
2831 // TMemberInfo
2832 // Local helper class to be able to compare data member represented by
2833 // 2 distinct TStreamerInfos
2834 class TMemberInfo {
2835 public:
2836 TClass *fParent;
2837 TString fName;
2838 TString fClassName;
2839 TString fComment;
2840 Int_t fDataType;
2841
2842 TMemberInfo(TClass *parent) : fParent(parent) {};
2843
2844 void SetDataType(Int_t datatype) {
2845 fDataType = datatype;
2846 }
2847
2848 void SetName(const char *name) {
2849 fName = name;
2850 }
2851 void SetClassName(const char *name) {
2853 }
2854 void SetComment(const char *title) {
2855 const char *left = strstr(title,"[");
2856 if (left) {
2857 const char *right = strstr(left,"]");
2858 if (right) {
2859 ++left;
2860 fComment.Append(left,right-left);
2861 }
2862 }
2863 }
2864 void Clear() {
2865 fName.Clear();
2866 fClassName.Clear();
2867 fComment.Clear();
2868 }
2869 /* Hide this not yet used implementation to suppress warnings message
2870 from icc 11
2871 Bool_t operator==(const TMemberInfo &other) {
2872 return fName==other.fName
2873 && fClassName == other.fClassName
2874 && fComment == other.fComment;
2875 }
2876 */
2877 Bool_t operator!=(const TMemberInfo &other) {
2878 if (fName != other.fName) return kTRUE;
2879 if (fDataType < TStreamerInfo::kObject) {
2880 // For simple type, let compare the data type
2881 if (fDataType != other.fDataType) {
2882 if ( (fDataType == 4 && other.fDataType == 16)
2883 || (fDataType == 16 && other.fDataType == 4) ) {
2884 // long and 'long long' have the same file format
2885 } else if ( (fDataType == 14 && other.fDataType == 17)
2886 || (fDataType == 17 && other.fDataType == 14) ) {
2887 // unsigned long and 'unsigned long long' have the same file format
2888 } else if ( (fDataType == 3 && other.fDataType == 6)
2889 ||(fDataType == 6 && other.fDataType == 3) ){
2890 // Int_t and kCounter. As the switch from Int_t (3) to
2891 // kCounter (6) might be triggered by a derived class using
2892 // the field as an array size, the class itself has no
2893 // control on what the field type really use.
2894 } else {
2895 return kTRUE;
2896 }
2897 }
2898 } else if (fClassName != other.fClassName) {
2899 if ( (fClassName == "long" && (other.fClassName == "long long" || other.fClassName == "Long64_t"))
2900 || ( (fClassName == "long long" || fClassName == "Long64_t") && other.fClassName == "long") ) {
2901 // This is okay both have the same on file format.
2902 } else if ( (fClassName == "unsigned long" && (other.fClassName == "unsigned long long" || other.fClassName == "ULong64_t"))
2903 || ( (fClassName == "unsigned long long" || fClassName == "ULong64_t") && other.fClassName == "unsigned long") ) {
2904 // This is okay both have the same on file format.
2905 } else if (TClassEdit::IsSTLCont(fClassName)) {
2908 if (name != othername) {
2911 if (!CollectionMatch(cl,otherCl)) {
2914 return kTRUE;
2915 }
2916 }
2917 }
2918 } else {
2919 return kTRUE;
2920 }
2921 }
2922 return fComment != other.fComment;
2923 }
2924 };
2925}
2926
2927////////////////////////////////////////////////////////////////////////////////
2928/// Emulated a call ShowMembers() on the obj of this class type, passing insp and parent.
2929
2931{
2932 TIter next(fElements);
2934
2936
2937 for (; element; element = (TStreamerElement*) next()) {
2938
2939 // Skip elements which have not been allocated memory.
2940 if (element->GetOffset() == kMissing) {
2941 continue;
2942 }
2943
2944 char* eaddr = ((char*)obj) + element->GetOffset();
2945
2946 if (element->IsBase()) {
2947 // Nothing to do this round.
2948 } else if (element->IsaPointer()) {
2949 elementName.Form("*%s",element->GetFullName());
2950 insp.Inspect(fClass, insp.GetParent(), elementName.Data(), eaddr, isTransient);
2951 } else {
2952 insp.Inspect(fClass, insp.GetParent(), element->GetFullName(), eaddr, isTransient);
2953 Int_t etype = element->GetType();
2954 switch(etype) {
2955 case kObject:
2956 case kAny:
2957 case kTObject:
2958 case kTString:
2959 case kTNamed:
2960 case kSTL:
2961 {
2962 TClass *ecl = element->GetClassPointer();
2963 if (ecl && (fClass!=ecl /* This happens 'artificially for stl container see the use of "This" */)) {
2964 insp.InspectMember(ecl, eaddr, TString(element->GetName()) + ".", isTransient);
2965 }
2966 break;
2967 }
2968 } // switch(etype)
2969 } // if IsaPointer()
2970 } // Loop over elements
2971
2972 // And now do the base classes
2973 next.Reset();
2974 element = (TStreamerElement*) next();
2975 for (; element; element = (TStreamerElement*) next()) {
2976 if (element->IsBase()) {
2977 // Skip elements which have not been allocated memory.
2978 if (element->GetOffset() == kMissing) {
2979 continue;
2980 }
2981
2982 char* eaddr = ((char*)obj) + element->GetOffset();
2983
2984 TClass *ecl = element->GetClassPointer();
2985 if (ecl) {
2986 ecl->CallShowMembers(eaddr, insp, isTransient);
2987 }
2988 } // If is a abse
2989 } // Loop over elements
2990}
2991
2992////////////////////////////////////////////////////////////////////////////////
2993/// Make a clone of an object using the Streamer facility.
2994/// If newname is specified, this will be the name of the new object.
2995
2997{
2999 if (newname && newname[0] && fName != newname) {
3000 TObjArray *newelems = newinfo->GetElements();
3001 Int_t ndata = newelems->GetEntriesFast();
3002 for(Int_t i = 0; i < ndata; ++i) {
3003 TObject *element = newelems->UncheckedAt(i);
3004 if (element->IsA() == TStreamerLoop::Class()) {
3006 if (fName == eloop->GetCountClass()) {
3007 eloop->SetCountClass(newname);
3008 eloop->Init();
3009 }
3010 } else if (element->IsA() == TStreamerBasicPointer::Class()) {
3012 if (fName == eptr->GetCountClass()) {
3013 eptr->SetCountClass(newname);
3014 eptr->Init();
3015 }
3016 }
3017 }
3018 }
3019 ++fgCount;
3020 newinfo->fNumber = fgCount;
3021 return newinfo;
3022}
3023
3024////////////////////////////////////////////////////////////////////////////////
3025/// Return True if the current StreamerInfo in cl or info is equivalent to this TStreamerInfo.
3026///
3027/// In this context 'Equivalent' means the same number of persistent data member which the same actual C++ type and
3028/// the same name.
3029/// If 'warn' is true, Warning message are printed to explicit the differences.
3030/// If 'complete' is false, stop at the first error, otherwise continue until all members have been checked.
3031
3033{
3035 R__ASSERT( (cl==0 || info==0) && (cl!=0 || info!=0) /* must compare to only one thing! */);
3036
3037 TString name;
3038 TString type;
3041
3042 TIter next(GetElements());
3043 TIter infonext((TList*)0);
3044 TIter basenext((TList*)0);
3045 TIter membernext((TList*)0);
3046 if (info) {
3047 infonext = info->GetElements();
3048 }
3049 if (cl) {
3050 TList *tlb = cl->GetListOfBases();
3051 if (tlb) { // Loop over bases
3052 basenext = tlb;
3053 }
3054 tlb = cl->GetListOfDataMembers();
3055 if (tlb) {
3056 membernext = tlb;
3057 }
3058 }
3059
3060 // First let's compare base classes
3061 Bool_t done = kFALSE;
3064 while(!done) {
3065 localClass.Clear();
3066 otherClass.Clear();
3067 el = (TStreamerElement*)next();
3068 if (el && el->IsBase()) {
3069 localClass = el->GetName();
3070 } else {
3071 el = 0;
3072 }
3073 if (cl) {
3075 if (tbc) {
3076 otherClass = tbc->GetName();
3077 } else if (el==0) {
3078 done = kTRUE;
3079 break;
3080 }
3081 } else {
3083 if (infoel && infoel->IsBase()) {
3084 otherClass = infoel->GetName();
3085 } else if (el==0) {
3086 done = kTRUE;
3087 break;
3088 }
3089 }
3093 }
3094 // Need to normalize the name
3095 if (localClass != otherClass) {
3096 if (warn) {
3097 if (el==0) {
3098 Warning("CompareContent",
3099 "The in-memory layout version %d for class '%s' has a base class (%s) that the on-file layout version %d does not have.",
3101 } else if (otherClass.Length()==0) {
3102 Warning("CompareContent",
3103 "The on-file layout version %d for class '%s' has a base class (%s) that the in-memory layout version %d does not have",
3105 } else {
3106 Warning("CompareContent",
3107 "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'",
3109 }
3110 }
3111 if (!complete) return kFALSE;
3112 result = result && kFALSE;
3113 }
3114 if (cl) {
3115 TStreamerBase *localBase = dynamic_cast<TStreamerBase*>(el);
3116 if (!localBase) continue;
3117 // We already have localBaseClass == otherBaseClass
3118 TClass *otherBaseClass = localBase->GetClassPointer();
3119 if (!otherBaseClass) continue;
3120 if (otherBaseClass->IsVersioned() && localBase->GetBaseVersion() != otherBaseClass->GetClassVersion()) {
3121 TString msg;
3122 msg.Form(" The StreamerInfo of class %s read from %s%s\n"
3123 " has the same version (=%d) as the active class but a different checksum.\n"
3124 " You should update the version to ClassDef(%s,%d).\n"
3125 " The objects on this file might not be readable because:\n"
3126 " 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).",
3127 GetName(), file ? "file " : "", file ? file->GetName() : "", fClassVersion, GetName(), fClassVersion + 1,
3128 GetClassVersion(), GetName(), otherClass.Data(), otherBaseClass->GetClassVersion(),
3129 GetClassVersion(), localBase->GetBaseVersion(), localClass.Data());
3131 otherBase->SetErrorMessage(msg);
3132
3133 } else if (!otherBaseClass->IsVersioned() && localBase->GetBaseCheckSum() != otherBaseClass->GetCheckSum()) {
3134 TVirtualStreamerInfo *localBaseInfo = otherBaseClass->FindStreamerInfo(localBase->GetBaseCheckSum());
3135 if (!localBaseInfo) {
3136 // We are likely in the situation where the base class comes after the derived
3137 // class in the TFile's list of StreamerInfo, so it has not yet been loaded,
3138 // let's see if it is there.
3139 const TList *list = file->GetStreamerInfoCache();
3140 localBaseInfo = list ? (TStreamerInfo*)list->FindObject(localBase->GetName()) : 0;
3141 }
3142 if (!localBaseInfo) {
3143 TString msg;
3144 msg.Form(" The StreamerInfo of the base class %s (of class %s) read from %s%s\n"
3145 " refers to a checksum (%x) that can not be found neither in memory nor in the file.\n",
3146 otherBaseClass->GetName(), localClass.Data(),
3147 file ? "file " : "", file ? file->GetName() : "",
3148 localBase->GetBaseCheckSum()
3149 );
3151 otherBase->SetErrorMessage(msg);
3152 continue;
3153 }
3154 if (localBaseInfo->CompareContent(otherBaseClass,0,kFALSE,kFALSE,file) ) {
3155 // They are equivalent, no problem.
3156 continue;
3157 }
3158 TString msg;
3159 msg.Form(" The StreamerInfo of class %s read from %s%s\n"
3160 " has the same version (=%d) as the active class but a different checksum.\n"
3161 " You should update the version to ClassDef(%s,%d).\n"
3162 " The objects on this file might not be readable because:\n"
3163 " 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).",
3164 GetName(), file ? "file " : "", file ? file->GetName() : "", fClassVersion, GetName(), fClassVersion + 1,
3165 GetClassVersion(), GetName(), otherClass.Data(), otherBaseClass->GetCheckSum(),
3166 GetClassVersion(), localBase->GetBaseCheckSum(), localClass.Data());
3168 otherBase->SetErrorMessage(msg);
3169 }
3170 } else {
3171 TStreamerBase *localBase = dynamic_cast<TStreamerBase*>(el);
3172 TStreamerBase *otherBase = dynamic_cast<TStreamerBase*>(infoel);
3173 if (!localBase || !otherBase) continue;
3174
3175 // We already have localBaseClass == otherBaseClass
3176 TClass *otherBaseClass = localBase->GetClassPointer();
3177 if (otherBaseClass->IsVersioned() && localBase->GetBaseVersion() != otherBase->GetBaseVersion()) {
3178 TString msg;
3179 msg.Form(" The StreamerInfo of class %s read from %s%s\n"
3180 " has the same version (=%d) as the active class but a different checksum.\n"
3181 " You should update the version to ClassDef(%s,%d).\n"
3182 " The objects on this file might not be readable because:\n"
3183 " 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).",
3184 GetName(), file ? "file " : "", file ? file->GetName() : "", fClassVersion, GetName(), fClassVersion + 1,
3185 GetClassVersion(), GetName(), otherClass.Data(), otherBase->GetBaseVersion(),
3186 GetClassVersion(), localBase->GetBaseVersion(), localClass.Data());
3187 otherBase->SetErrorMessage(msg);
3188
3189 } else if (!otherBaseClass->IsVersioned() && localBase->GetBaseCheckSum() != otherBase->GetBaseCheckSum())
3190 {
3191 TVirtualStreamerInfo *localBaseInfo = otherBaseClass->FindStreamerInfo(localBase->GetBaseCheckSum());
3192 TVirtualStreamerInfo *otherBaseInfo = otherBaseClass->FindStreamerInfo(otherBase->GetBaseCheckSum());
3194 localBaseInfo->CompareContent(0,otherBaseInfo,kFALSE,kFALSE,file) ) {
3195 // They are equivalent, no problem.
3196 continue;
3197 }
3198 TString msg;
3199 msg.Form(" The StreamerInfo of class %s read from %s%s\n"
3200 " has the same version (=%d) as the active class but a different checksum.\n"
3201 " You should update the version to ClassDef(%s,%d).\n"
3202 " The objects on this file might not be readable because:\n"
3203 " 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).",
3204 GetName(), file ? "file " : "", file ? file->GetName() : "", fClassVersion, GetName(), fClassVersion + 1,
3205 GetClassVersion(), GetName(), otherClass.Data(), otherBase->GetBaseCheckSum(),
3206 GetClassVersion(), localBase->GetBaseCheckSum(), localClass.Data());
3207 otherBase->SetErrorMessage(msg);
3208 }
3209 }
3210 }
3211 if (!result && !complete) {
3212 return result;
3213 }
3214 // Next the datamembers
3215 done = kFALSE;
3216 next.Reset();
3217 infonext.Reset();
3218
3219 TMemberInfo local(GetClass());
3220 TMemberInfo other(cl ? cl : info->GetClass());
3221 while(!done) {
3222 local.Clear();
3223 other.Clear();
3224 el = (TStreamerElement*)next();
3225 while (el && (el->IsBase() || el->IsA() == TStreamerArtificial::Class())) {
3226 el = (TStreamerElement*)next();
3227 }
3228 if (el) {
3229 local.SetName( el->GetName() );
3230 local.SetClassName( el->GetTypeName() );
3231 local.SetComment( el->GetTitle() );
3232 local.SetDataType( el->GetType() );
3233 }
3234 if (cl) {
3236 while(tdm && ( (!tdm->IsPersistent()) || (tdm->Property()&kIsStatic) || (el && local.fName != tdm->GetName()) )) {
3238 }
3239 if (tdm) {
3240 other.SetName( tdm->GetName() );
3241 other.SetClassName( tdm->GetTrueTypeName() );
3242 other.SetComment( tdm->GetTitle() );
3243 if (tdm->GetDataType()) {
3244 // Need to update the type for arrays.
3245 if (tdm->IsaPointer()) {
3246 if (tdm->GetDataType()->GetType() == TVirtualStreamerInfo::kChar && !tdm->GetArrayDim() && tdm->GetArrayIndex()[0]==0) {
3248 } else {
3249 other.SetDataType( tdm->GetDataType()->GetType() + TVirtualStreamerInfo::kOffsetP);
3250 }
3251 } else {
3252 if (tdm->GetArrayDim()) {
3253 other.SetDataType( tdm->GetDataType()->GetType() + TVirtualStreamerInfo::kOffsetL);
3254 } else {
3255 other.SetDataType( tdm->GetDataType()->GetType() );
3256 }
3257 }
3258 }
3259 } else if (el==0) {
3260 done = kTRUE;
3261 break;
3262 }
3263 } else {
3265 while (infoel && (infoel->IsBase() || infoel->IsA() == TStreamerArtificial::Class())) {
3267 }
3268 if (infoel) {
3269 other.SetName( infoel->GetName() );
3270 other.SetClassName( infoel->GetTypeName() );
3271 other.SetComment( infoel->GetTitle() );
3272 other.SetDataType( infoel->GetType() );
3273 } else if (el==0) {
3274 done = kTRUE;
3275 break;
3276 }
3277 }
3278 if (local!=other) {
3279 if (warn) {
3280 if (!el) {
3281 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"
3282 " %s %s; //%s"
3284 ,other.fClassName.Data(),other.fName.Data(),other.fComment.Data());
3285
3286 } else if (other.fName.Length()==0) {
3287 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"
3288 " %s %s; //%s"
3290 ,local.fClassName.Data(),local.fName.Data(),local.fComment.Data());
3291 } else {
3292 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"
3293 " %s %s; //%s\n"
3294 "vs\n"
3295 " %s %s; //%s"
3297 ,local.fClassName.Data(),local.fName.Data(),local.fComment.Data()
3298 ,other.fClassName.Data(),other.fName.Data(),other.fComment.Data());
3299 }
3300 }
3301 result = result && kFALSE;
3302 if (!complete) return result;
3303 }
3304 }
3305 return result;
3306}
3307
3308
3309////////////////////////////////////////////////////////////////////////////////
3310/// Compute total size of all persistent elements of the class
3311
3313{
3314 if (this == fClass->GetCurrentStreamerInfo()) {
3317 return;
3318 }
3319 }
3320
3322 //faster and more precise to use last element offset +size
3323 //on 64 bit machines, offset may be forced to be a multiple of 8 bytes
3324 fSize = element ? element->GetOffset() + element->GetSize() : 0;
3325 if (fNVirtualInfoLoc > 0 && (fVirtualInfoLoc[0]+sizeof(TStreamerInfo*)) >= (ULong_t)fSize) {
3326 fSize = fVirtualInfoLoc[0] + sizeof(TStreamerInfo*);
3327 }
3328
3329 // On some platform and in some case of layout non-basic data types needs
3330 // to be aligned. So let's be on the safe side and align on the size of
3331 // the pointers. (Question: is that the right thing on x32 ABI ?)
3332 constexpr size_t kSizeOfPtr = sizeof(void*);
3333 if ((fSize % kSizeOfPtr) != 0 && !fClass->IsSyntheticPair()) {
3335 }
3336}
3337
3338////////////////////////////////////////////////////////////////////////////////
3339/// Recursively mark streamer infos for writing to a file.
3340///
3341/// Will force this TStreamerInfo to the file and also
3342/// all the dependencies.
3343/// If argument force > 0 the loop on class dependencies is forced.
3344/// This function is called when streaming a class that contains
3345/// a null pointer. In this case, the TStreamerInfo for the class
3346/// with the null pointer must be written to the file and also all
3347/// the TStreamerInfo of all the classes referenced by the class.
3348/// We must be given a file to write to.
3349
3351{
3352 if (!file || fNumber < 0) {
3353 return;
3354 }
3355 // Get the given file's list of streamer infos marked for writing.
3356 TArrayC* cindex = file->GetClassIndex();
3357 //the test below testing fArray[fNumber]>1 is to avoid a recursivity
3358 //problem in some cases like:
3359 // class aProblemChild: public TNamed {
3360 // aProblemChild *canBeNull;
3361 // };
3362 if ( // -- Done if already marked, and we are not forcing, or forcing is blocked.
3363 (cindex->fArray[fNumber] && !force) || // Streamer info is already marked, and not forcing, or
3364 (cindex->fArray[fNumber] > 1) // == 2 means ignore forcing to prevent infinite recursion.
3365 ) {
3366 return;
3367 }
3368
3370 {
3372 if (contentClass->Property() & kIsAbstract) {
3373 // If the class of the element is abstract, register the
3374 // TStreamerInfo only if it has already been built.
3375 // Otherwise call cl->GetStreamerInfo() would generate an
3376 // incorrect StreamerInfo.
3377 si = contentClass->GetCurrentStreamerInfo();
3378 } else {
3379 si = contentClass->GetStreamerInfo();
3380 }
3381 if (si) {
3382 si->ForceWriteInfo(file, force);
3383 }
3384 };
3385
3386 // We do not want to write streamer info to the file
3387 // for std::string.
3388 static TClassRef string_classref("string");
3389 if (fClass == string_classref) { // We are std::string.
3390 return;
3391 }
3392 // We do not want to write streamer info to the file
3393 // for STL containers.
3394 if (fClass==0) {
3395 // Build or BuildCheck has not been called yet.
3396 // Let's use another means of checking.
3397 if (fElements && fElements->GetEntriesFast()==1 && strcmp("This",fElements->UncheckedAt(0)->GetName())==0) {
3398 // We are an STL collection.
3399 return;
3400 }
3401 } else if (fClass->GetCollectionProxy()) { // We are an STL collection.
3403 if (valueClass)
3405 return;
3406 }
3407 // Mark ourselves for output, and block
3408 // forcing to prevent infinite recursion.
3409 cindex->fArray[fNumber] = 2;
3410 // Signal the file that the marked streamer info list has changed.
3411 cindex->fArray[0] = 1;
3412 // Recursively mark the streamer infos for
3413 // all of our elements.
3414 TIter next(fElements);
3416 for (; element; element = (TStreamerElement*) next()) {
3417 if (element->IsTransient()) continue;
3418 TClass* cl = element->GetClassPointer();
3419 if (cl)
3421 }
3422
3423}
3424
3425////////////////////////////////////////////////////////////////////////////////
3426/// Assuming that obj points to (the part of) an object that is of the
3427/// type described by this streamerInfo, return the actual type of the
3428/// object (i.e. the type described by this streamerInfo is a base class
3429/// of the actual type of the object.
3430/// This routine should only be called if the class described by this
3431/// StreamerInfo is 'emulated'.
3432
3434{
3436
3437 if (fNVirtualInfoLoc != 0) {
3438 TStreamerInfo *allocator = *(TStreamerInfo**)( (const char*)obj + fVirtualInfoLoc[0] );
3439 if (allocator) return allocator->GetClass();
3440 }
3441 return (TClass*)fClass;
3442}
3443
3444////////////////////////////////////////////////////////////////////////////////
3445/// Return true if the checksum passed as argument is one of the checksum
3446/// value produced by the older checksum calculation algorithm.
3447
3449{
3450 for(UInt_t i = 1; i < TClass::kLatestCheckSum; ++i) {
3451 if ( checksum == GetCheckSum( (TClass::ECheckSum) i) ) return kTRUE;
3452 }
3453 return kFALSE;
3454}
3455
3456////////////////////////////////////////////////////////////////////////////////
3457/// Recalculate the checksum of this TStreamerInfo based on its code.
3458///
3459/// The class ckecksum is used by the automatic schema evolution algorithm
3460/// to uniquely identify a class version.
3461/// The check sum is built from the names/types of base classes and
3462/// data members.
3463/// The valid range of code is determined by ECheckSum.
3464/// - kNoEnum: data members of type enum are not counted in the checksum
3465/// - kNoRange: return the checksum of data members and base classes, not including the ranges and array size found in comments.
3466/// - kWithTypeDef: use the sugared type name in the calculation.
3467///
3468/// This is needed for backward compatibility.
3469/// ### WARNING
3470/// This function must be kept in sync with TClass::GetCheckSum.
3471/// They are both used to handle backward compatibility and should both return the same values.
3472/// TStreamerInfo uses the information in TStreamerElement while TClass uses the information
3473/// from TClass::GetListOfBases and TClass::GetListOfDataMembers.
3474/// Original algorithm from Victor Perevovchikov (perev@bnl.gov).
3475
3477{
3478 // kCurrentCheckSum (0) should be kept for backward compatibility, to be
3479 // able to use the inequality checks, we need to set the code to the largest
3480 // value.
3482
3483 UInt_t id = 0;
3484
3485 int il;
3486 TString name = GetName();
3487 TString type;
3488 il = name.Length();
3489 for (int i=0; i<il; i++) id = id*3+name[i];
3490
3491 TIter next(GetElements());
3493 // Here we skip he base classes in case this is a pair or STL collection,
3494 // otherwise, on some STL implementations, it can happen that pair has
3495 // base classes which are an internal implementation detail.
3497 while ( (el=(TStreamerElement*)next())) { // loop over bases
3498 if (el->IsBase()) {
3499 name = el->GetName();
3500 il = name.Length();
3501 for (int i=0; i<il; i++) id = id*3+name[i];
3502 if (code > TClass::kNoBaseCheckSum && el->IsA() == TStreamerBase::Class()) {
3503 TStreamerBase *base = (TStreamerBase*)el;
3504 id = id*3 + base->GetBaseCheckSum();
3505 }
3506 }
3507 } /* End of Base Loop */
3508 }
3509
3510 next.Reset();
3511 while ( (el=(TStreamerElement*)next()) ) {
3512 if (el->IsBase()) continue;
3513
3514 // humm can we tell if a TStreamerElement is an enum?
3515 // Maybe something like:
3517 if ( el->GetType()==3 && gROOT->GetType(el->GetTypeName())==0) {
3518 // If the type is not an enum but a typedef to int then
3519 // el->GetTypeName() should be return 'int'
3520 isenum = kTRUE;
3521 }
3522 if ( (code > TClass::kNoEnum) && isenum) id = id*3 + 1;
3523
3524 name = el->GetName(); il = name.Length();
3525
3526 int i;
3527 for (i=0; i<il; i++) id = id*3+name[i];
3528
3529 if (code == TClass::kReflex || code == TClass::kReflexNoComment) {
3530 // With TClass::kReflexV5 we do not want the Long64 in the name
3531 // nor any typedef.
3532 type = TClassEdit::ResolveTypedef(el->GetTypeName(),kTRUE);
3533
3534 } else if (code <= TClass::kWithTypeDef) {
3535 // humm ... In the streamerInfo we only have the desugared/normalized
3536 // names, so we are unable to calculate the name with typedefs ...
3537 // except for the case of the ROOT typedef (Int_t, etc.) which are
3538 // kept by TClassEdit::ResolveTypedef(typeName) but not by TCling's
3539 // normalization ...
3540 //
3541 type = el->GetTypeName();
3542 } else {
3544 }
3547 }
3548 if (code == TClass::kReflex || code == TClass::kReflexNoComment) {
3549 type.ReplaceAll("ULong64_t","unsigned long long");
3550 type.ReplaceAll("Long64_t","long long");
3551 type.ReplaceAll("signed char","char");
3552 type.ReplaceAll("<signed char","<char");
3553 type.ReplaceAll(",signed char",",char");
3554 if (type=="signed char") type = "char";
3555 }
3556
3557 il = type.Length();
3558 for (i=0; i<il; i++) id = id*3+type[i];
3559
3560 int dim = el->GetArrayDim();
3561 if (dim) {
3562 for (i=0;i<dim;i++) id = id*3+el->GetMaxIndex(i);
3563 }
3564
3565
3566 if (code > TClass::kNoRange) {
3567 const char *left;
3568 if (code > TClass::kNoRangeCheck)
3570 else
3571 left = strstr(el->GetTitle(),"[");
3572 if (left) {
3573 const char *right = strstr(left,"]");
3574 if (right) {
3575 ++left;
3576 while (left != right) {
3577 id = id*3 + *left;
3578 ++left;
3579 }
3580 }
3581 }
3582 }
3583 }
3584 return id;
3585}
3586
3587////////////////////////////////////////////////////////////////////////////////
3588
3589static void R__WriteConstructorBody(FILE *file, TIter &next)
3590{
3592 next.Reset();
3593 while ((element = (TStreamerElement*)next())) {
3598 if(element->GetArrayLength() <= 1) {
3599 fprintf(file," %s = 0;\n",element->GetName());
3600 } else {
3601 fprintf(file," memset(%s,0,%d);\n",element->GetName(),element->GetSize());
3602 }
3603 }
3604 if (TVirtualStreamerInfo::kOffsetP <= element->GetType() && element->GetType() < TVirtualStreamerInfo::kObject ) {
3605 fprintf(file," %s = 0;\n",element->GetName());
3606 }
3607 }
3608}
3609
3610static constexpr int str_length(const char* str)
3611{
3612 return *str ? 1 + str_length(str + 1) : 0;
3613}
3614
3615////////////////////////////////////////////////////////////////////////////////
3616/// Return true if the element is auto_ptr or unique_ptr
3617
3619
3620 constexpr auto auto_ptr_len = str_length("auto_ptr<");
3621 constexpr auto unique_ptr_len = str_length("unique_ptr<");
3622
3623 const char *name = element->GetTypeNameBasic();
3624
3625 return ((strncmp(name, "auto_ptr<", auto_ptr_len) == 0)
3626 || (strncmp(name, "unique_ptr<", unique_ptr_len) == 0));
3627}
3628
3629////////////////////////////////////////////////////////////////////////////////
3630/// Write down the pointers and arrays part of the body of the 'move' constructor.
3631
3633{
3635 next.Reset();
3637 while ((element = (TStreamerElement*)next())) {
3641 {
3642 if (!defMod) { fprintf(file," %s &modrhs = const_cast<%s &>( rhs );\n",protoname.Data(),protoname.Data()); defMod = kTRUE; };
3643 const char *ename = element->GetName();
3644 const char *colon2 = strstr(ename,"::");
3645 if (colon2) ename = colon2+2;
3646 if(element->GetArrayLength() <= 1) {
3647 fprintf(file," modrhs.%s = 0;\n",ename);
3648 } else {
3649 fprintf(file," memset(modrhs.%s,0,%d);\n",ename,element->GetSize());
3650 }
3651 } else {
3652 const char *ename = element->GetName();
3653 if (element->GetType() == kCharStar) {
3654 if (!defMod) {
3655 fprintf(file," %s &modrhs = const_cast<%s &>( rhs );\n",protoname.Data(),protoname.Data()); defMod = kTRUE;
3656 };
3657 fprintf(file," modrhs.%s = 0;\n",ename);
3658 } else if (TVirtualStreamerInfo::kOffsetP <= element->GetType() && element->GetType() < TVirtualStreamerInfo::kObject ) {
3659 if (!defMod) {
3660 fprintf(file," %s &modrhs = const_cast<%s &>( rhs );\n",protoname.Data(),protoname.Data()); defMod = kTRUE;
3661 };
3662 fprintf(file," modrhs.%s = 0;\n",ename);
3663 } else if (element->GetArrayLength() > 1) {
3664 // FIXME: Need to add support for variable length array.
3665 if (element->GetArrayDim() == 1) {
3666 fprintf(file," for (Int_t i=0;i<%d;i++) %s[i] = rhs.%s[i];\n",element->GetArrayLength(),ename,ename);
3667 } else if (element->GetArrayDim() >= 2) {
3668 fprintf(file," for (Int_t i=0;i<%d;i++) reinterpret_cast<%s *>(%s", element->GetArrayLength(), element->GetTypeName(), ename);
3669 fprintf(file,")[i] = reinterpret_cast<%s const *>(rhs.%s)[i];\n", element->GetTypeName(), ename);
3670 }
3671 } else if (element->GetType() == TVirtualStreamerInfo::kSTLp) {
3672 if (!defMod) { fprintf(file," %s &modrhs = const_cast<%s &>( rhs );\n",protoname.Data(),protoname.Data()); defMod = kTRUE; };
3673 fprintf(file," modrhs.%s = 0;\n",ename);
3674 } else if (element->GetType() == TVirtualStreamerInfo::kSTL) {
3675 if (!defMod) {
3676 fprintf(file," %s &modrhs = const_cast<%s &>( rhs );\n",protoname.Data(),protoname.Data()); defMod = kTRUE;
3677 }
3678 TClass *cle = element->GetClassPointer();
3679 TVirtualCollectionProxy *proxy = cle ? element->GetClassPointer()->GetCollectionProxy() : 0;
3680 std::string method_name = "clear";
3681 if (!element->TestBit(TStreamerElement::kDoNotDelete) && proxy && (((TStreamerSTL*)element)->GetSTLtype() == ROOT::kSTLbitset)) {
3682 method_name = "reset";
3683 }
3684 if (element->IsBase()) {
3685 fprintf(file," modrhs.%s();\n", method_name.c_str());
3686 } else {
3687 fprintf(file," modrhs.%s.%s();\n",ename, method_name.c_str());
3688 }
3689 }
3690 }
3691 }
3692}
3693
3694////////////////////////////////////////////////////////////////////////////////
3695/// Write down the body of the 'move' constructor.
3696
3697static void R__WriteMoveConstructorBody(FILE *file, const TString &protoname, TIter &next)
3698{
3700 next.Reset();
3702 while ((element = (TStreamerElement*)next())) {
3703 if (element->IsBase()) {
3704 if (atstart) { fprintf(file," : "); atstart = kFALSE; }
3705 else fprintf(file," , ");
3706 fprintf(file, "%s(const_cast<%s &>( rhs ))\n", element->GetName(),protoname.Data());
3707 } else {
3708 if (element->GetArrayLength() <= 1) {
3709 if (atstart) { fprintf(file," : "); atstart = kFALSE; }
3710 else fprintf(file," , ");
3711 if (R__IsUniquePtr(element)) {
3712 fprintf(file, "%s(const_cast<%s &>( rhs ).%s.release() )\n",element->GetName(),protoname.Data(),element->GetName());
3713 } else {
3714 fprintf(file, "%s(const_cast<%s &>( rhs ).%s)\n",element->GetName(),protoname.Data(),element->GetName());
3715 }
3716 }
3717 }
3718 }
3719 fprintf(file,"{\n");
3720 fprintf(file," // This is NOT a copy constructor. This is actually a move constructor (for stl container's sake).\n");
3721 fprintf(file," // Use at your own risk!\n");
3722 fprintf(file," (void)rhs; // avoid warning about unused parameter\n");
3723
3725}
3726
3727////////////////////////////////////////////////////////////////////////////////
3728/// Write down the body of the 'move' constructor.
3729
3731{
3732 fprintf(file,"{\n");
3733 fprintf(file," // This is NOT a copy operator=. This is actually a move operator= (for stl container's sake).\n");
3734 fprintf(file," // Use at your own risk!\n");
3735 fprintf(file," (void)rhs; // avoid warning about unused parameter\n");
3736
3738 next.Reset();
3739 while ((element = (TStreamerElement*)next())) {
3740 if (element->IsBase()) {
3741 fprintf(file, " %s::operator=(const_cast<%s &>( rhs ));\n", element->GetName(),protoname.Data());
3742 } else {
3743 if (element->GetArrayLength() <= 1) {
3744 if (R__IsUniquePtr(element)) {
3745 fprintf(file, " %s = std::move((const_cast<%s &>( rhs ).%s));\n",element->GetName(),protoname.Data(),element->GetName());
3746 } else {
3747 fprintf(file, " %s = (const_cast<%s &>( rhs ).%s);\n",element->GetName(),protoname.Data(),element->GetName());
3748 }
3749 }
3750 }
3751 }
3752
3754
3755 fprintf(file, " return *this;\n");
3756}
3757
3758////////////////////////////////////////////////////////////////////////////////
3759
3760static void R__WriteDestructorBody(FILE *file, TIter &next)
3761{
3763 next.Reset();
3764 while ((element = (TStreamerElement*)next())) {
3768 {
3769 const char *ename = element->GetName();
3770 const char *colon2 = strstr(ename,"::");
3771 if (colon2) ename = colon2+2;
3773 if(element->GetArrayLength() <= 1) {
3774 fprintf(file," %s = 0;\n",ename);
3775 } else {
3776 fprintf(file," memset(%s,0,%d);\n",ename,element->GetSize());
3777 }
3778 } else {
3779 if(element->GetArrayLength() <= 1) {
3780 fprintf(file," delete %s; %s = 0;\n",ename,ename);
3781 } else {
3782 fprintf(file," for (Int_t i=0;i<%d;i++) delete %s[i]; memset(%s,0,%d);\n",element->GetArrayLength(),ename,ename,element->GetSize());
3783 }
3784 }
3785 }
3786 if (element->GetType() == TVirtualStreamerInfo::kCharStar) {
3787 const char *ename = element->GetName();
3789 fprintf(file," %s = 0;\n",ename);
3790 } else {
3791 fprintf(file," delete [] %s; %s = 0;\n",ename,ename);
3792 }
3793 }
3794 if (TVirtualStreamerInfo::kOffsetP <= element->GetType() && element->GetType() < TVirtualStreamerInfo::kObject ) {
3795 const char *ename = element->GetName();
3797 fprintf(file," %s = 0;\n",ename);
3798 } else if (element->HasCounter()) {
3799 fprintf(file," delete %s; %s = 0;\n",ename,ename);
3800 } else {
3801 fprintf(file," delete [] %s; %s = 0;\n",ename,ename);
3802 }
3803 }
3804 if (element->GetType() == TVirtualStreamerInfo::kSTL || element->GetType() == TVirtualStreamerInfo::kSTLp) {
3805 const char *ename = element->GetName();
3806 const char *prefix = "";
3807 if ( element->GetType() == TVirtualStreamerInfo::kSTLp ) {
3808 prefix = "*";
3809 } else if ( element->IsBase() ) {
3810 ename = "this";
3811 }
3812 TClass *cle = element->GetClassPointer();
3813 TVirtualCollectionProxy *proxy = cle ? element->GetClassPointer()->GetCollectionProxy() : 0;
3814 if (!element->TestBit(TStreamerElement::kDoNotDelete) && proxy) {
3815 Int_t stltype = ((TStreamerSTL*)element)->GetSTLtype();
3816
3817 if (proxy->HasPointers()) {
3818 fprintf(file," std::for_each( (%s %s).rbegin(), (%s %s).rend(), DeleteObjectFunctor() );\n",prefix,ename,prefix,ename);
3819 //fprintf(file," %s::iterator iter;\n");
3820 //fprintf(file," %s::iterator begin = (%s %s).begin();\n");
3821 //fprintf(file," %s::iterator end (%s %s).end();\n");
3822 //fprintf(file," for( iter = begin; iter != end; ++iter) { delete *iter; }\n");
3823 } else {
3826 std::vector<std::string> inside;
3827 int nestedLoc;
3829 if ((!inside[1].empty() && inside[1][inside[1].size()-1]=='*')
3830 || (!inside[2].empty() && inside[2][inside[2].size()-1]=='*')) {
3831 fprintf(file," std::for_each( (%s %s).rbegin(), (%s %s).rend(), DeleteObjectFunctor() );\n",prefix,ename,prefix,ename);
3832 }
3833 }
3834 }
3835 }
3836 if ( prefix[0] ) {
3837 fprintf(file," delete %s; %s = 0;\n",ename,ename);
3838 }
3839 }
3840 }
3841}
3842
3843////////////////////////////////////////////////////////////////////////////////
3844/// Write the Declaration of class.
3845
3847{
3848 if (fClassVersion == -3) {
3849 return;
3850 }
3851
3854 const char *clname = GetName();
3856 if (strchr(clname, ':')) {
3857 // We might have a namespace in front of the classname.
3859 const char *name = clname;
3860 UInt_t nest = 0;
3861 UInt_t pr_pos = 0;
3862 for (Int_t cur = 0; cur < len; ++cur) {
3863 switch (clname[cur]) {
3864 case '<':
3865 ++nest;
3866 pr_pos = cur;
3867 isTemplate = kTRUE;
3868 break;
3869 case '>':
3870 if (nest == 0) { cur = len; continue; } // the name is not well formed, give up.
3871 --nest;
3872 break;
3873 case ':': {
3874 if (nest == 0 && clname[cur+1] == ':') {
3875 // We have a scope
3877 name = clname + cur + 2;
3878 }
3879 break;
3880 }
3881 }
3882 }
3883 if (isTemplate) {
3885 }
3886 clname = name;
3887 } else {
3888 const char *where = strstr(clname, "<");
3889 isTemplate = where != 0;
3890 if (isTemplate) {
3892 }
3893 }
3894
3897 fprintf(fp, "#ifndef %s_h\n", templateName.Data());
3898 fprintf(fp, "#define %s_h\n", templateName.Data());
3899 }
3900
3903
3904 // Generate class statement with base classes.
3906 TIter next(fElements);
3907 Int_t nbase = 0;
3908 while ((element = (TStreamerElement*)next())) {
3909 if (!element->IsBase()) continue;
3910 nbase++;
3911 const char *ename = element->GetName();
3912 if (nbase == 1) fprintf(fp," : public %s",ename);
3913 else fprintf(fp," , public %s",ename);
3914 }
3915 fprintf(fp," {\n");
3916
3917 // Generate forward declaration nested classes.
3918 if (subClasses && subClasses->GetEntries()) {
3919 Bool_t needheader = true;
3920
3923 Int_t len = strlen(GetName());
3924 while ((subinfo = (TStreamerInfo*)subnext())) {
3925 if (strncmp(GetName(),subinfo->GetName(),len)==0 && (subinfo->GetName()[len]==':') ) {
3926 if (subinfo->GetName()[len+1]==':' && strstr(subinfo->GetName()+len+2,":")==0) {
3927 if (needheader) {
3928 fprintf(fp,"\npublic:\n");
3929 fprintf(fp,"// Nested classes forward declaration.\n");
3930 needheader = false;
3931 }
3935 if (subinfo->GetClassVersion() == -3) {
3937 } else {
3939 fprintf(fp, ";\n");
3940 }
3941
3942 for (UInt_t i = 0;i < sub_numberOfClasses;++i) {
3943 fprintf(fp, "}; // end of class.\n");
3944 }
3945 if (sub_numberOfNamespaces > 0) {
3946 Error("GenerateDeclaration","Nested classes %s thought to be inside a namespace inside the class %s",subinfo->GetName(),GetName());
3947 }
3948 }
3949 }
3950 }
3951 }
3952
3953 fprintf(fp,"\npublic:\n");
3954 fprintf(fp,"// Nested classes declaration.\n");
3955
3956 // Generate nested classes.
3957 if (subClasses && subClasses->GetEntries()) {
3960 Int_t len = strlen(GetName());
3961 while ((subinfo = (TStreamerInfo*)subnext())) {
3962 if (strncmp(GetName(),subinfo->GetName(),len)==0 && (subinfo->GetName()[len]==':')) {
3963 if (subinfo->GetName()[len+1]==':' && strstr(subinfo->GetName()+len+2,":")==0) {
3964 subinfo->GenerateDeclaration(fp, sfp, subClasses, kFALSE);
3965 }
3966 }
3967 }
3968 }
3969
3970 fprintf(fp,"\npublic:\n");
3971 fprintf(fp,"// Data Members.\n");
3972
3973 {
3974 // Generate data members.
3975 TString name(128);
3976 Int_t ltype = 12;
3977 Int_t ldata = 10;
3978 Int_t lt,ld,is;
3979 TString line;
3980 line.Resize(kMaxLen);
3981 next.Reset();
3982 while ((element = (TStreamerElement*)next())) {
3983
3984 if (element->IsBase()) continue;
3985 const char *ename = element->GetName();
3986
3987 name = ename;
3988 for (Int_t i=0;i < element->GetArrayDim();i++) {
3989 name += TString::Format("[%d]",element->GetMaxIndex(i));
3990 }
3991 name += ";";
3992 ld = name.Length();
3993
3994 TString enamebasic = element->GetTypeNameBasic();
3995 if (element->IsA() == TStreamerSTL::Class()) {
3996 // If we have a map, multimap, set or multiset,
3997 // and the key is a class, we need to replace the
3998 // container by a vector since we don't have the
3999 // comparator function.
4000 Int_t stltype = ((TStreamerSTL*)element)->GetSTLtype();
4001 switch (stltype) {
4002 case ROOT::kSTLmap:
4003 case ROOT::kSTLmultimap:
4004 case ROOT::kSTLset:
4005 case ROOT::kSTLmultiset:
4008 {
4010 }
4011 default:
4012 // nothing to do.
4013 break;
4014 }
4015 } else if (strncmp(enamebasic.Data(), "auto_ptr<", std::char_traits<char>::length("auto_ptr<")) == 0) {
4017 }
4018
4019 lt = enamebasic.Length();
4020
4021 line = " ";
4022 line += enamebasic;
4023 if (lt>=ltype) ltype = lt+1;
4024
4025 for (is = 3+lt; is < (3+ltype); ++is) line += ' ';
4026
4027 line += name;
4028 if (element->IsaPointer() && !strchr(line,'*')) line[2+ltype] = '*';
4029
4030 if (ld>=ldata) ldata = ld+1;
4031 for (is = 3+ltype+ld; is < (3+ltype+ldata); ++is) line += ' ';
4032
4033 line += " //";
4034 line += element->GetTitle();
4035 fprintf(fp,"%s\n",line.Data());
4036 }
4037 }
4039 // Generate default functions, ClassDef and trailer.
4040 fprintf(fp,"\n %s() {\n",protoname.Data());
4041 R__WriteConstructorBody(fp,next);
4042 fprintf(fp," }\n");
4043 fprintf(fp," %s(%s && ) = default;\n",protoname.Data(),protoname.Data());
4044 fprintf(fp," %s &operator=(const %s & rhs)\n ",protoname.Data(),protoname.Data());
4046 fprintf(fp," }\n");
4047 fprintf(fp," %s(const %s & rhs )\n ",protoname.Data(),protoname.Data());
4049 fprintf(fp," }\n");
4050 fprintf(fp," virtual ~%s() {\n ",protoname.Data());
4051 R__WriteDestructorBody(fp,next);
4052 fprintf(fp," }\n\n");
4053
4054 } else {
4055 // Generate default functions, ClassDef and trailer.
4056 fprintf(fp,"\n %s();\n",protoname.Data());
4057 fprintf(fp," %s(%s && ) = default;\n",protoname.Data(),protoname.Data());
4058 fprintf(fp," %s &operator=(const %s & );\n",protoname.Data(),protoname.Data());
4059 fprintf(fp," %s(const %s & );\n",protoname.Data(),protoname.Data());
4060 fprintf(fp," virtual ~%s();\n\n",protoname.Data());
4061
4062 // Add the implementations to the source.cxx file.
4064 fprintf(sfp,"#ifndef %s_cxx\n",guard.Data());
4065 fprintf(sfp,"#define %s_cxx\n",guard.Data());
4066 fprintf(sfp,"%s::%s() {\n",GetName(),protoname.Data());
4068 fprintf(sfp,"}\n");
4069
4070 fprintf(sfp,"%s &%s::operator=(const %s & rhs)\n",GetName(),GetName(),protoname.Data());
4072 fprintf(sfp,"}\n");
4073
4074 fprintf(sfp,"%s::%s(const %s & rhs)\n",GetName(),protoname.Data(),protoname.Data());
4076 fprintf(sfp,"}\n");
4077
4078 fprintf(sfp,"%s::~%s() {\n",GetName(),protoname.Data());
4080 fprintf(sfp,"}\n");
4081 fprintf(sfp,"#endif // %s_cxx\n\n",guard.Data());
4082 }
4083
4084 TClass *cl = gROOT->GetClass(GetName());
4085 // This `IsTObject` is a (easier to calculate) subset of 'base class has a virtual declaration' for
4086 // all the `ClassDef` virtual functions. Usually this means that the base class has one
4087 // of the ClassDef (without the NV suffix).
4088 const TString overrd = (cl && cl->IsTObject()) ? "Override" : "";
4089 if (fClassVersion > 1 || (cl && cl->IsTObject()) ) {
4090 // add 1 to class version in case we didn't manage reproduce the class layout to 100%.
4091 if (fClassVersion == 0) {
4092 // If the class was declared 'transient', keep it that way.
4093 fprintf(fp," ClassDef%s(%s,%d); // Generated by MakeProject.\n",overrd.Data(),protoname.Data(),0);
4094 } else {
4095 fprintf(fp," ClassDef%s(%s,%d); // Generated by MakeProject.\n",overrd.Data(),protoname.Data(),fClassVersion + 1);
4096 }
4097 }
4098 fprintf(fp,"};\n");
4099
4100 for(UInt_t i=0;i<numberOfNamespaces;++i) {
4101 fprintf(fp,"} // namespace\n");
4102 }
4103
4105 fprintf(fp,"#endif // generic template declaration\n");
4106 }
4107}
4108
4109////////////////////////////////////////////////////////////////////////////////
4110/// Add to the header file, the \#include need for this class.
4111
4113{
4114 if (inclist[0]==0) {
4115 // Always have this include for ClassDef.
4116 TMakeProject::AddInclude( fp, "Rtypes.h", kFALSE, inclist);
4117 }
4118 UInt_t ninc = 0;
4119
4120 const char *clname = GetName();
4121 if (strchr(clname,'<')) {
4122 // This is a template, we need to check the template parameter.
4124 }
4125
4126 TString name(1024);
4127 Int_t ltype = 10;
4128 Int_t ldata = 10;
4129 Int_t lt;
4130 Int_t ld;
4131 TIter next(fElements);
4134 while ((element = (TStreamerElement*)next())) {
4135 //if (element->IsA() == TStreamerBase::Class()) continue;
4136 const char *ename = element->GetName();
4137 const char *colon2 = strstr(ename,"::");
4138 if (colon2) ename = colon2+2;
4139 name = ename;
4140 for (Int_t i=0;i < element->GetArrayDim();i++) {
4141 name += TString::Format("[%d]",element->GetMaxIndex(i));
4142 }
4143 ld = name.Length();
4144 lt = strlen(element->GetTypeName());
4145 if (ltype < lt) ltype = lt;
4146 if (ldata < ld) ldata = ld;
4147
4148 //must include Riostream.h in case of an STL container
4149 if (!incRiostream && element->InheritsFrom(TStreamerSTL::Class())) {
4151 TMakeProject::AddInclude( fp, "Riostream.h", kFALSE, inclist);
4152 }
4153
4154 //get include file name if any
4155 const char *include = element->GetInclude();
4156 if (!include[0]) continue;
4157
4158 Bool_t greater = (include[0]=='<');
4159 include++;
4160
4161 if (strncmp(include,"include/",8)==0) {
4162 include += 8;
4163 }
4164 if (strncmp(include,"include\\",9)==0) {
4165 include += 9;
4166 }
4167 if (TClassEdit::IsStdPair(element->GetTypeName())) {
4168 TMakeProject::AddInclude( fp, "utility", kTRUE, inclist);
4169 } else if (strncmp(element->GetTypeName(),"auto_ptr<",std::char_traits<char>::length("auto_ptr<"))==0) {
4170 TMakeProject::AddInclude( fp, "memory", kTRUE, inclist);
4171 } else {
4175 }
4176
4177 if (strchr(element->GetTypeName(),'<')) {
4178 // This is a template, we need to check the template parameter.
4180 }
4181 }
4182 return ninc;
4183}
4184
4185////////////////////////////////////////////////////////////////////////////////
4186/// Generate header file for the class described by this TStreamerInfo
4187/// the function is called by TFile::MakeProject for each class in the file
4188
4190{
4191 // if (fClassVersion == -4) return 0;
4192 if ((fClass && fClass->GetCollectionType()) || TClassEdit::IsSTLCont(GetName())) return 0;
4193 if (TClassEdit::IsStdPair(GetName())) return 0;
4194 if (strncmp(GetName(),"auto_ptr<",std::char_traits<char>::length("auto_ptr<"))==0) return 0;
4195
4197 if (cl) {
4198 if (cl->HasInterpreterInfo()) return 0; // skip known classes
4199 }
4201 if (strchr(GetName(),':')) {
4202 UInt_t len = strlen(GetName());
4203 UInt_t nest = 0;
4204 UInt_t scope = 0;
4205 for(UInt_t i=len; i>0; --i) {
4206 switch(GetName()[i]) {
4207 case '>': ++nest; if (scope==0) { isTemplate = kTRUE; } break;
4208 case '<': --nest; break;
4209 case ':':
4210 if (nest==0 && GetName()[i-1]==':') {
4211 // We have a scope
4212 TString nsname(GetName(), i-1);
4213 cl = gROOT->GetClass(nsname);
4214 if (cl && (cl->Size()!=0 || (cl->Size()==0 && !cl->HasInterpreterInfo() /*empty 'base' class on file*/))) {
4215 // This class is actually nested.
4216 return 0;
4217 } else if (cl == 0 && extrainfos != 0) {
4219 if (clinfo && clinfo->GetClassVersion() == -5) {
4220 // This class is actually nested.
4221 return 0;
4222 }
4223 }
4224 ++scope;
4225 }
4226 break;
4227 }
4228 }
4229 }
4231
4232 if (gDebug) printf("generating code for class %s\n",GetName());
4233
4234 // Open the file
4235
4238 filename.Form("%s/%s.h",dirname,headername.Data());
4239
4240 FILE *fp = fopen(filename.Data(),"w");
4241 if (!fp) {
4242 Error("MakeProject","Cannot open output file:%s\n",filename.Data());
4243 return 0;
4244 }
4245
4246 filename.Form("%s/%sProjectHeaders.h",dirname,gSystem->BaseName(dirname));
4247 FILE *allfp = fopen(filename.Data(),"a");
4248 if (!allfp) {
4249 Error("MakeProject","Cannot open output file:%s\n",filename.Data());
4250 fclose(fp);
4251 return 0;
4252 }
4253 fprintf(allfp,"#include \"%s.h\"\n", headername.Data());
4254 fclose(allfp);
4255
4256 char *inclist = new char[50000];
4257 inclist[0] = 0;
4258
4259 // Generate class header.
4260 TDatime td;
4261 fprintf(fp,"//////////////////////////////////////////////////////////\n");
4262 fprintf(fp,"// This class has been generated by TFile::MakeProject\n");
4263 fprintf(fp,"// (%s by ROOT version %s)\n",td.AsString(),gROOT->GetVersion());
4264 fprintf(fp,"// from the StreamerInfo in file %s\n",gDirectory->GetFile()->GetName());
4265 fprintf(fp,"//////////////////////////////////////////////////////////\n");
4266 fprintf(fp,"\n");
4267 fprintf(fp,"\n");
4268 fprintf(fp,"#ifndef %s_h\n",headername.Data());
4269 fprintf(fp,"#define %s_h\n",headername.Data());
4271 fprintf(fp,"\n");
4272
4274 if (subClasses) {
4277 while ((subinfo = (TStreamerInfo*)subnext())) {
4278 subinfo->GenerateIncludes(fp, inclist, extrainfos);
4279 }
4280 }
4281 fprintf(fp,"\n");
4282
4283 TString sourcename; sourcename.Form( "%s/%sProjectSource.cxx", dirname, gSystem->BaseName(dirname) );
4284 FILE *sfp = fopen( sourcename.Data(), "a" );
4285 if (sfp) {
4287 } else {
4288 Error("GenerateHeaderFile","Could not open %s for appending",sourcename.Data());
4289 }
4291
4292 fprintf(fp,"#endif\n");
4293
4294 delete [] inclist;
4295 fclose(fp);
4296 if (sfp) fclose(sfp);
4297 return 1;
4298}
4299
4300////////////////////////////////////////////////////////////////////////////////
4301/// Compute data member offset.
4302/// Return pointer to the Streamer function if one exists
4303
4305{
4307 char dmbracket[256];
4308 snprintf(dmbracket,255,"%s[",dm->GetName());
4310 if (!fClass->IsLoaded()) {
4311 // If the 'class' is not loaded, we do not have a TClass bootstrap and thus
4312 // the 'RealData' might not have enough information because of the lack
4313 // of proper ShowMember implementation.
4314 if (! (dm->Property() & kIsStatic) ) {
4315 // Give an offset only to non-static members.
4316 offset = dm->GetOffset();
4317 }
4318 }
4319 TRealData *rdm;
4320 while ((rdm = (TRealData*)nextr())) {
4321 char *rdmc = (char*)rdm->GetName();
4322 //next statement required in case a class and one of its parent class
4323 //have data members with the same name
4324 if (dm->IsaPointer() && rdmc[0] == '*') rdmc++;
4325
4326 if (rdm->GetDataMember() != dm) continue;
4327 if (strcmp(rdmc,dm->GetName()) == 0) {
4328 offset = rdm->GetThisOffset();
4329 streamer = rdm->GetStreamer();
4330 break;
4331 }
4332 if (strcmp(rdm->GetName(),dm->GetName()) == 0) {
4333 if (rdm->IsObject()) {
4334 offset = rdm->GetThisOffset();
4335 streamer = rdm->GetStreamer();
4336 break;
4337 }
4338 }
4339 if (strstr(rdm->GetName(),dmbracket)) {
4340 offset = rdm->GetThisOffset();
4341 streamer = rdm->GetStreamer();
4342 break;
4343 }
4344 }
4345 return offset;
4346}
4347
4348////////////////////////////////////////////////////////////////////////////////
4349/// Return the offset of the data member as indicated by this StreamerInfo.
4350
4352{
4353 if (elementName == 0) return 0;
4354
4355 Int_t offset = 0;
4357 if (elem) offset = elem->GetOffset();
4358
4359 return offset;
4360}
4361
4362////////////////////////////////////////////////////////////////////////////////
4363/// Return total size of all persistent elements of the class (with offsets).
4364
4366{
4367 return fSize;
4368}
4369
4370////////////////////////////////////////////////////////////////////////////////
4371/// Return total size of all persistent elements of the class
4372/// use GetSize if you want to get the real size in memory.
4373
4375{
4376 TIter next(fElements);
4378 Int_t asize = 0;
4379 while ((element = (TStreamerElement*)next())) {
4380 asize += element->GetSize();
4381 }
4382 return asize;
4383}
4384
4385////////////////////////////////////////////////////////////////////////////////
4386/// Return the StreamerElement of "datamember" inside our
4387/// class or any of its base classes.
4388///
4389/// The offset information
4390/// contained in the StreamerElement is related to its immediately
4391/// containing class, so we return in 'offset' the offset inside
4392/// our class.
4393
4395{
4396 if (!fElements) {
4397 return 0;
4398 }
4399
4400 // Look first at the data members and base classes
4401 // of our class.
4403 if (element) {
4404 offset = element->GetOffset();
4405 return element;
4406 }
4407
4408 // Not found, so now try the data members and base classes
4409 // of the base classes of our class.
4410 if (fClass->HasDataMemberInfo()) {
4411 // Our class has a dictionary loaded, use it to search the base classes.
4413 TBaseClass* base = 0;
4414 TClass* base_cl = 0;
4415 Int_t base_offset = 0;
4416 Int_t local_offset = 0;
4418 // Iterate on list of base classes.
4419 while ((base = (TBaseClass*) nextb())) {
4420 base_cl = TClass::GetClass(base->GetName());
4422 if (!base_cl || !base_element) {
4423 continue;
4424 }
4425 base_offset = base_element->GetOffset();
4427 if (element) {
4429 return element;
4430 }
4431 }
4432 } else {
4433 // Our class's dictionary is not loaded. Search through the base class streamer elements.
4434 TIter next(fElements);
4436 while ((curelem = (TStreamerElement*) next())) {
4437 if (curelem->InheritsFrom(TStreamerBase::Class())) {
4438 TClass* baseClass = curelem->GetClassPointer();
4439 if (!baseClass) {
4440 continue;
4441 }
4442 Int_t base_offset = curelem->GetOffset();
4443 Int_t local_offset = 0;
4445 if (baseClass->Property() & kIsAbstract) {
4446 baseInfo = (TStreamerInfo*)baseClass->GetStreamerInfoAbstractEmulated();
4447 } else {
4448 baseInfo = (TStreamerInfo*)baseClass->GetStreamerInfo();
4449 }
4450 if (baseInfo) element = baseInfo->GetStreamerElement(datamember, local_offset);
4451 if (element) {
4453 return element;
4454 }
4455 }
4456 }
4457 }
4458 return 0;
4459}
4460
4461////////////////////////////////////////////////////////////////////////////////
4462/// <b>Obsolete</b>: this routine is obsolete and should not longer be used.
4463///
4464/// TStreamerInfo holds two types of data structures
4465/// - TObjArray* fElements; containing the list of all TStreamerElement
4466/// objects for this class version.
4467/// - ULong_t* fElem; containing the preprocessed information
4468/// by TStreamerInfo::Compile In case consecutive data members
4469/// are of the same type, the Compile function declares the consecutive
4470/// elements as one single element in fElems.
4471///
4472/// Example with the class TAttLine:
4473/// ~~~{.cpp}
4474/// TClass::GetClass("TAttLine")->GetStreamerInfo()->ls(); produces;
4475/// StreamerInfo for class: TAttLine, version=1
4476/// short fLineColor offset= 4 type= 2 line color
4477/// short fLineStyle offset= 6 type= 2 line style
4478/// short fLineWidth offset= 8 type= 2 line width
4479/// i= 0, fLineColor type= 22, offset= 4, len=3, method=0
4480/// ~~~
4481/// For I/O implementations (eg. XML) , one has to know the original name
4482/// of the data member. This function can be used to return a pointer
4483/// to the original TStreamerElement object corresponding to the j-th
4484/// element of a compressed array in fElems.
4485/// Parameters description:
4486/// - i: the serial number in array fElem
4487/// - j: the element number in the array of consecutive types
4488/// In the above example the class TAttLine has 3 consecutive data members
4489/// of the same type "short". Compile makes one single array of 3 elements.
4490/// To access the TStreamerElement for the second element
4491/// of this array, one can call:
4492/// ~~~{.cpp}
4493/// auto el = GetStreamerElementReal(0,1);
4494/// auto membername = el->GetName();
4495/// ~~~
4496/// This function is typically called from TBuffer, TXmlBuffer.
4497
4499{
4500 ::Obsolete("TStreamerInfo::GetStreamerElementReal", "v5-34-20", "v6-00-02");
4501
4502 if (i < 0 || i >= fNdata) return 0;
4503 if (j < 0) return 0;
4504 if (!fElements) return 0;
4506 if (!se) return 0;
4508 for (Int_t ise=0;ise < nelems;ise++) {
4509 if (se != (TStreamerElement*)fElements->UncheckedAt(ise)) continue;
4510 if (ise+j >= nelems) return 0;
4512 }
4513 return 0;
4514}
4515
4516////////////////////////////////////////////////////////////////////////////////
4517/// Get the value from inside a collection.
4518
4519template <typename T>
4521{
4522 if (type>=kConv && type<kSTL) {
4523 type -= kConv;
4524 }
4525 switch (type) {
4526 // basic types
4527 case kBool: {Bool_t *val = (Bool_t*)ladd; return T(*val);}
4528 case kChar: {Char_t *val = (Char_t*)ladd; return T(*val);}
4529 case kShort: {Short_t *val = (Short_t*)ladd; return T(*val);}
4530 case kInt: {Int_t *val = (Int_t*)ladd; return T(*val);}
4531 case kLong: {Long_t *val = (Long_t*)ladd; return T(*val);}
4532 case kLong64: {Long64_t *val = (Long64_t*)ladd; return T(*val);}
4533 case kFloat: {Float_t *val = (Float_t*)ladd; return T(*val);}
4534 case kFloat16: {Float_t *val = (Float_t*)ladd; return T(*val);}
4535 case kDouble: {Double_t *val = (Double_t*)ladd; return T(*val);}
4536 case kDouble32: {Double_t *val = (Double_t*)ladd; return T(*val);}
4537 case kUChar: {UChar_t *val = (UChar_t*)ladd; return T(*val);}
4538 case kUShort: {UShort_t *val = (UShort_t*)ladd; return T(*val);}
4539 case kUInt: {UInt_t *val = (UInt_t*)ladd; return T(*val);}
4540 case kULong: {ULong_t *val = (ULong_t*)ladd; return T(*val);}
4541#if defined(_MSC_VER) && (_MSC_VER <= 1200)
4542 case kULong64: {Long64_t *val = (Long64_t*)ladd; return T(*val);}
4543#else
4544 case kULong64: {ULong64_t *val= (ULong64_t*)ladd; return T(*val);}
4545#endif
4546 case kBits: {UInt_t *val = (UInt_t*)ladd; return T(*val);}
4547
4548 // array of basic types array[8]
4549 case kOffsetL + kBool: {Bool_t *val = (Bool_t*)ladd; return T(val[k]);}
4550 case kOffsetL + kChar: {Char_t *val = (Char_t*)ladd; return T(val[k]);}
4551 case kOffsetL + kShort: {Short_t *val = (Short_t*)ladd; return T(val[k]);}
4552 case kOffsetL + kInt: {Int_t *val = (Int_t*)ladd; return T(val[k]);}
4553 case kOffsetL + kLong: {Long_t *val = (Long_t*)ladd; return T(val[k]);}
4554 case kOffsetL + kLong64: {Long64_t *val = (Long64_t*)ladd; return T(val[k]);}
4555 case kOffsetL + kFloat: {Float_t *val = (Float_t*)ladd; return T(val[k]);}
4556 case kOffsetL + kFloat16: {Float_t *val = (Float_t*)ladd; return T(val[k]);}
4557 case kOffsetL + kDouble: {Double_t *val = (Double_t*)ladd; return T(val[k]);}
4558 case kOffsetL + kDouble32:{Double_t *val = (Double_t*)ladd; return T(val[k]);}
4559 case kOffsetL + kUChar: {UChar_t *val = (UChar_t*)ladd; return T(val[k]);}
4560 case kOffsetL + kUShort: {UShort_t *val = (UShort_t*)ladd; return T(val[k]);}
4561 case kOffsetL + kUInt: {UInt_t *val = (UInt_t*)ladd; return T(val[k]);}
4562 case kOffsetL + kULong: {ULong_t *val = (ULong_t*)ladd; return T(val[k]);}
4563#if defined(_MSC_VER) && (_MSC_VER <= 1200)
4564 case kOffsetL + kULong64: {Long64_t *val = (Long64_t*)ladd; return T(val[k]);}
4565#else
4566 case kOffsetL + kULong64:{ULong64_t *val= (ULong64_t*)ladd; return T(val[k]);}
4567#endif
4568
4569#define READ_ARRAY(TYPE_t) \
4570 { \
4571 Int_t sub_instance, index; \
4572 Int_t instance = k; \
4573 if (len) { \
4574 index = instance / len; \
4575 sub_instance = instance % len; \
4576 } else { \
4577 index = instance; \
4578 sub_instance = 0; \
4579 } \
4580 TYPE_t **val =(TYPE_t**)(ladd); \
4581 return T((val[sub_instance])[index]); \
4582 }
4583
4584 // pointer to an array of basic types array[n]
4585 case (unsigned)kOffsetP + kBool_t: READ_ARRAY(Bool_t)
4586 case (unsigned)kOffsetP + kChar_t: READ_ARRAY(Char_t)
4587 case (unsigned)kOffsetP + kShort_t: READ_ARRAY(Short_t)
4588 case (unsigned)kOffsetP + kInt_t: READ_ARRAY(Int_t)
4589 case (unsigned)kOffsetP + kLong_t: READ_ARRAY(Long_t)
4590 case (unsigned)kOffsetP + kLong64_t: READ_ARRAY(Long64_t)
4591 case (unsigned)kOffsetP + kFloat16_t:
4592 case (unsigned)kOffsetP + kFloat_t: READ_ARRAY(Float_t)
4593 case (unsigned)kOffsetP + kDouble32_t:
4594 case (unsigned)kOffsetP + kDouble_t: READ_ARRAY(Double_t)
4595 case (unsigned)kOffsetP + kUChar_t: READ_ARRAY(UChar_t)
4596 case (unsigned)kOffsetP + kUShort_t: READ_ARRAY(UShort_t)
4597 case (unsigned)kOffsetP + kUInt_t: READ_ARRAY(UInt_t)
4598 case (unsigned)kOffsetP + kULong_t: READ_ARRAY(ULong_t)
4599#if defined(_MSC_VER) && (_MSC_VER <= 1200)
4600 case (unsigned)kOffsetP + kULong64_t: READ_ARRAY(Long64_t)
4601#else
4602 case (unsigned)kOffsetP + kULong64_t: READ_ARRAY(ULong64_t)
4603#endif
4604
4605 // array counter //[n]
4606 case kCounter: {Int_t *val = (Int_t*)ladd; return T(*val);}
4607 }
4608 return 0;
4609}
4610
4611
4612
4613template Double_t TStreamerInfo::GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const;
4614template Long64_t TStreamerInfo::GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const;
4615template LongDouble_t TStreamerInfo::GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const;
4616
4617////////////////////////////////////////////////////////////////////////////////
4618/// Return value of element i in object at pointer.
4619/// The function may be called in two ways:
4620/// - method1 len < 0: i is assumed to be the TStreamerElement number i in StreamerInfo
4621/// - method2 len >= 0: i is the type, address of variable is directly pointer.
4622
4623template <typename T>
4625{
4626 char *ladd;
4627 Int_t atype;
4628 if (len >= 0) {
4629 ladd = pointer;
4630 atype = i;
4631 } else {
4632 if (i < 0) return 0;
4633 ladd = pointer + fCompFull[i]->fOffset;
4634 atype = fCompFull[i]->fNewType;
4636 if (atype == kSTL) {
4638 if (newClass == 0) {
4640 }
4641 TClass *innerClass = newClass->GetCollectionProxy()->GetValueClass();
4642 if (innerClass) {
4643 return 0; // We don't know which member of the class we would want.
4644 } else {
4645 TVirtualCollectionProxy *proxy = newClass->GetCollectionProxy();
4646 // EDataType is a subset of TStreamerInfo::EReadWrite
4649 Int_t nc = proxy->Size();
4650 if (j >= nc) return 0;
4651 char *element_ptr = (char*)proxy->At(j);
4653 }
4654 }
4655 }
4657}
4658
4659////////////////////////////////////////////////////////////////////////////////
4660
4661template Double_t TStreamerInfo::GetTypedValueClones<Double_t>(TClonesArray *clones, Int_t i, Int_t j, int k, Int_t eoffset) const;
4664
4665template <typename T>
4667{
4668 // return value of element i in object number j in a TClonesArray and eventually
4669 // element k in a sub-array.
4670
4671 Int_t nc = clones->GetEntriesFast();
4672 if (j >= nc) return 0;
4673
4674 char *pointer = (char*)clones->UncheckedAt(j);
4675 char *ladd = pointer + eoffset + fCompFull[i]->fOffset;
4676 return GetTypedValueAux<T>(fCompFull[i]->fType,ladd,k,((TStreamerElement*)fCompFull[i]->fElem)->GetArrayLength());
4677}
4678
4682
4683////////////////////////////////////////////////////////////////////////////////
4684/// Return value of element i in object number j in an STL container and eventually
4685/// element k in a sub-array.
4686
4687template <typename T>
4689{
4690 Int_t nc = cont->Size();
4691 if (j >= nc) return 0;
4692
4693 char *pointer = (char*)cont->At(j);
4694 char *ladd = pointer + eoffset + fCompFull[i]->fOffset;
4695 return GetTypedValueAux<T>(fCompFull[i]->fType,ladd,k,((TStreamerElement*)fCompFull[i]->fElem)->GetArrayLength());
4696}
4697
4701
4702////////////////////////////////////////////////////////////////////////////////
4703/// Return value of element i in object number j in a pointer to STL container and eventually
4704/// element k in a sub-array.
4705
4706template <typename T>
4708{
4709 Int_t nc = cont->Size();
4710
4711 if (j >= nc) return 0;
4712
4713 char **ptr = (char**)cont->At(j);
4714 char *pointer = *ptr;
4715
4716 char *ladd = pointer + eoffset + fCompFull[i]->fOffset;
4717 return GetTypedValueAux<T>(fCompFull[i]->fType,ladd,k,((TStreamerElement*)fCompFull[i]->fElem)->GetArrayLength());
4718}
4719
4720////////////////////////////////////////////////////////////////////////////////
4721/// Insert new members as expressed in the array of TSchemaRule(s).
4722
4723void TStreamerInfo::InsertArtificialElements(std::vector<const ROOT::TSchemaRule*> &rules)
4724{
4725 if (rules.empty()) return;
4726
4727 TIter next(fElements);
4728 UInt_t count = 0;
4729
4730 for(auto rule : rules) {
4731 if( rule->IsRenameRule() || rule->IsAliasRule() )
4732 continue;
4733 next.Reset();
4735 while ((element = (TStreamerElement*) next())) {
4736 if ( rule->HasTarget( element->GetName() ) ) {
4737
4738 // Check whether this is an 'attribute' rule.
4739 if ( rule->GetAttributes()[0] != 0 ) {
4740 TString attr( rule->GetAttributes() );
4741 attr.ToLower();
4742 if (attr.Contains("owner")) {
4743 if (attr.Contains("notowner")) {
4745 } else {
4747 }
4748 }
4749
4750 }
4751 break;
4752 }
4753 }
4754
4755 auto canIgnore = [](const ROOT::TSchemaRule *r) {
4756 if (r->GetAttributes()[0] != 0) {
4757 TString attr(r->GetAttributes());
4758 attr.ToLower();
4759 return attr.Contains("canignore");
4760 } else
4761 return false;
4762 };
4763 // NOTE: Before adding the rule we should check that the source do
4764 // existing in this StreamerInfo.
4765 const TObjArray *sources = rule->GetSource();
4766 if (sources)
4768 auto source_element = dynamic_cast<TStreamerElement *>(GetElements()->FindObject(src->GetName()));
4769 if (!source_element) {
4770 // It might still be in one the base classes.
4771 if (fClass->GetListOfRealData() && !fClass->GetListOfRealData()->FindObject(src->GetName())) {
4772 // Missing source.
4773 if (!canIgnore(rule)) {
4775 rule->AsString(ruleStr);
4776 Warning("InsertArtificialElements",
4777 "For class %s in StreamerInfo %d is missing the source data member `%s` when trying to "
4778 "apply the "
4779 "rule:\n %s",
4780 GetName(), GetClassVersion(), src->GetName(), ruleStr.Data());
4781 }
4782 rule = nullptr;
4783 break;
4784 }
4785 } else {
4786 // The source exists, let's check if it has the expected type.
4788 if ((memClass != source_element->GetNewClass() || memType != source_element->GetNewType()) &&
4790 const char *dim = src->GetDimensions();
4792 rule->AsString(ruleStr);
4793 auto cl = source_element->GetNewClass();
4795 if (memClass != cl) {
4796 classmsg = "and the memory TClass is \"";
4797 classmsg += cl ? cl->GetName() : "nullptr";
4798 classmsg += "\" while the rule needed \"";
4799 classmsg += memClass ? memClass->GetName() : "nullptr";
4800 classmsg += "\"";
4801 }
4802 Error("InsertArtificialElements",
4803 "For class %s in StreamerInfo %d a rule has conflicting type for the source \"%s %s%s\",\n"
4804 " The TStreamerElement has memory type %d (needed %d) %s:\n %s",
4805 GetName(), GetClassVersion(), src->GetTypeForDeclaration().Data(), src->GetName(),
4806 dim && dim[0] ? dim : "", source_element->GetNewType(), memType, classmsg.Data(),
4807 ruleStr.Data());
4808 rule = nullptr;
4809 break;
4810 }
4811 }
4812 }
4813
4814 if (!rule) continue;
4815
4817 std::vector<TStreamerArtificial*> toAdd;
4818
4819 if (rule->GetTarget()==0) {
4821 newName.Form("%s_rule%d",fClass->GetName(),count);
4825 "void");
4827 newel->SetReadFunc( rule->GetReadFunctionPointer() );
4828 newel->SetReadRawFunc( rule->GetReadRawFunctionPointer() );
4829 toAdd.push_back(newel);
4830 } else {
4831 toAdd.reserve(rule->GetTarget()->GetEntriesFast());
4832 TObjString * objstr = (TObjString*)(rule->GetTarget()->At(0));
4833 if (objstr) {
4834 TString newName = objstr->String();
4836 if ( TDataMember* dm = fClass->GetDataMember( newName ) ) {
4839 TStreamerInfo::kArtificial, dm->GetTypeName());
4840 newel->SetReadFunc( rule->GetReadFunctionPointer() );
4841 newel->SetReadRawFunc( rule->GetReadRawFunctionPointer() );
4842 toAdd.push_back(newel);
4843 } else {
4844 // This would be a completely new member (so it would need to be cached)
4845 // TOBEDONE
4846 }
4847 for(Int_t other = 1; other < rule->GetTarget()->GetEntriesFast(); ++other) {
4848 objstr = (TObjString*)(rule->GetTarget()->At(other));
4849 if (objstr) {
4850 newName = objstr->String();
4851 if ( TDataMember* dm = fClass->GetDataMember( newName ) ) {
4854 TStreamerInfo::kArtificial, dm->GetTypeName());
4855 toAdd.push_back(newel);
4856 }
4857 }
4858 }
4859 } // For each target of the rule
4860 }
4861 // Now find where with need to add them
4862 TIter s_iter(rule->GetSource());
4863 Int_t loc = -1;
4864 while( TObjString *s = (TObjString*)s_iter() ) {
4865 for(Int_t i = fElements->GetLast(); i >= 0 && (i+1) >= loc; --i) {
4866 if (s->String() == fElements->UncheckedAt(i)->GetName()) {
4867 if (loc == -1 || (i+1)>loc) {
4868 loc = i+1;
4869 }
4870 }
4871 }
4872 }
4873 if (loc == -1) {
4874 // Verify if the last one is not 'skipped'.
4875 for(Int_t i = fElements->GetLast(); i >= 0 && (i+1) >= loc; --i) {
4878 break;
4879 }
4880 loc = i;
4881 }
4882 }
4883 if (loc == -1) {
4884 for(auto &el : toAdd) {
4885 fElements->Add(el);
4886 }
4887 } else {
4889 }
4890 } // None of the target of the rule are on file.
4891}
4892
4893////////////////////////////////////////////////////////////////////////////////
4894/// List the TStreamerElement list and also the precomputed tables
4895/// if option contains the string "incOrig", also prints the original
4896/// (non-optimized elements in the list of compiled elements.
4897
4899{
4900 if (fClass && (fName != fClass->GetName())) {
4901 if (fClass->IsVersioned()) {
4902 Printf("\nStreamerInfo for conversion to %s from: %s, version=%d, checksum=0x%x",fClass->GetName(),GetName(),fClassVersion,GetCheckSum());
4903 } else {
4904 Printf("\nStreamerInfo for conversion to %s from: %s, checksum=0x%x",fClass->GetName(),GetName(),GetCheckSum());
4905 }
4906 } else {
4907 if (!fClass || fClass->IsVersioned()) {
4908 Printf("\nStreamerInfo for class: %s, version=%d, checksum=0x%x",GetName(),fClassVersion,GetCheckSum());
4909 } else {
4910 Printf("\nStreamerInfo for class: %s, checksum=0x%x",GetName(),GetCheckSum());
4911 }
4912 }
4913
4914 if (fElements) {
4915 TIter next(fElements);
4916 TObject *obj;
4917 while ((obj = next()))
4918 obj->ls(option);
4919 }
4920 Bool_t noaddr = option && (strstr(option,"noaddr") != nullptr);
4921
4922 if (strstr(option,"full") != 0) {
4923 for (Int_t i=0; i < fNfulldata; ++i) {
4926 element->GetSequenceType(sequenceType);
4927 // by definition of the loop (i+1) <= fNdata
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(),fCompFull[i]->fType,fCompFull[i]->fOffset,fCompFull[i]->fLength, (noaddr ? 0 : fCompFull[i]->fMethod),
4934 sequenceType.Data());
4935 }
4936
4937 } else {
4938 Bool_t wantOrig = strstr(option,"incOrig") != 0;
4940 for (Int_t i=0,j=0;i < fNdata;++i,++j) {
4943 element->GetSequenceType(sequenceType);
4944 // by definition of the loop (i+1) <= fNdata
4946 if (optimized) {
4947 // This was optimized.
4948 if (sequenceType.Length() != 0) {
4949 sequenceType += ',';
4950 }
4951 sequenceType += "optimized";
4952 }
4953 if (sequenceType.Length()) {
4954 sequenceType.Prepend(" [");
4955 sequenceType += "]";
4956 }
4957 Printf(" i=%2d, %-15s type=%3d, offset=%3d, len=%d, method=%ld%s",
4958 i,element->GetName(),fCompOpt[i]->fType,fCompOpt[i]->fOffset,fCompOpt[i]->fLength, (noaddr ? 0 : fCompOpt[i]->fMethod),
4959 sequenceType.Data());
4960 if (optimized && wantOrig) {
4961 Bool_t done;
4962 do {
4963 element = (TStreamerElement*)fCompFull[j]->fElem;
4964 element->GetSequenceType(sequenceType);
4965 if (sequenceType.Length()) {
4966 sequenceType.Prepend(" [");
4967 sequenceType += "]";
4968 }
4969 Printf(" j=%2d, %-15s type=%3d, offset=%3d, len=%d, method=%ld%s",
4971 sequenceType.Data());
4972 ++j;
4973 done = j >= fNfulldata || ( (i+1 < fNdata) && fCompOpt[i+1]->fElem == fCompFull[j+1]->fElem );
4974 } while (!done);
4975
4976 }
4977 }
4978 }
4979}
4980
4981////////////////////////////////////////////////////////////////////////////////
4982/// An emulated object is created at address obj, if obj is null we
4983/// allocate memory for the object.
4984
4985void* TStreamerInfo::New(void *obj)
4986{
4987 //???FIX ME: What about varying length array elements?
4988
4989 char* p = (char*) obj;
4990
4991 TIter next(fElements);
4992
4993 if (!p) {
4994 // Allocate and initialize the memory block.
4995 p = new char[fSize];
4996 memset(p, 0, fSize);
4997 }
4998
4999 next.Reset();
5001
5002 for (; element; element = (TStreamerElement*) next()) {
5003
5004 // Skip elements which have not been allocated memory.
5005 if (element->GetOffset() == kMissing) {
5006 continue;
5007 }
5008
5009 // Skip elements for which we do not have any class
5010 // information. FIXME: Document how this could happen.
5011 TClass *cle = element->GetNewClass();
5012 if (!cle)
5013 cle = element->GetClassPointer();
5014 if (!cle)
5015 continue;
5016
5017 char* eaddr = p + element->GetOffset();
5018 Int_t etype = element->GetNewType();
5019 if (etype == TStreamerInfo::kNoType)
5020 etype = element->GetType();
5021
5022 //cle->GetStreamerInfo(); //necessary in case "->" is not specified
5023
5024 switch (etype) {
5025
5026 case kAnyP:
5027 case kObjectP:
5028 case kSTLp:
5029 {
5030 // Initialize array of pointers with null pointers.
5031 char** r = (char**) eaddr;
5032 Int_t len = element->GetArrayLength();
5033 for (Int_t i = 0; i < len; ++i) {
5034 r[i] = 0;
5035 }
5036 }
5037 break;
5038
5039 case kObjectp:
5040 case kAnyp:
5041 {
5042 // If the option "->" is given in the data member comment field
5043 // it is assumed that the object exists before reading data in,
5044 // so we create an object.
5045 if (cle != TClonesArray::Class()) {
5046 void** r = (void**) eaddr;
5047 *r = cle->New();
5048 } else {
5049 // In the case of a TClonesArray, the class name of
5050 // the contained objects must be specified in the
5051 // data member comment in this format:
5052 // TClonesArray* myVar; //->(className)
5053 const char* title = element->GetTitle();
5054 const char* bracket1 = strrchr(title, '(');
5055 const char* bracket2 = strrchr(title, ')');
5056 if (bracket1 && bracket2 && (bracket2 != (bracket1 + 1))) {
5057 Int_t len = bracket2 - (bracket1 + 1);
5058 char* clonesClass = new char[len+1];
5059 clonesClass[0] = '\0';
5061 void** r = (void**) eaddr;
5062 *r = (void*) new TClonesArray(clonesClass);
5063 delete[] clonesClass;
5064 } else {
5065 //Warning("New", "No class name found for TClonesArray initializer in data member comment (expected \"//->(className)\"");
5066 void** r = (void**) eaddr;
5067 *r = (void*) new TClonesArray();
5068 }
5069 }
5070 }
5071 break;
5072
5073 case kBase:
5074 {
5075 if (cle->Property() & kIsAbstract) {
5076 TVirtualStreamerInfo *einfo = cle->GetStreamerInfoAbstractEmulated();
5077 if (einfo) einfo->New(eaddr);
5078 } else {
5079 cle->New(eaddr);
5080 }
5081 break;
5082 }
5083 case kObject:
5084 case kAny:
5085 case kTObject:
5086 case kTString:
5087 case kTNamed:
5088 {
5089 cle->New(eaddr);
5090 }
5091 break;
5092
5093 case kSTL:
5094 {
5095 if (strcmp(element->GetName(),"This")==0 &&
5096 !cle->GetCollectionProxy()) {
5097 // missing information, avoid infinite loop
5098 // by doing nothing ....
5099 } else {
5100 if (cle->GetCollectionProxy())
5101 cle->GetCollectionProxy()->New(eaddr);
5102 else
5103 cle->New(eaddr);
5104 }
5105 }
5106 break;
5107
5108 case kObject + kOffsetL:
5109 case kAny + kOffsetL:
5110 case kTObject + kOffsetL:
5111 case kTString + kOffsetL:
5112 case kTNamed + kOffsetL:
5113 case kSTL + kOffsetL:
5114 {
5115 Int_t size = cle->Size();
5116 char* r = eaddr;
5117 Int_t len = element->GetArrayLength();
5118 for (Int_t i = 0; i < len; ++i, r += size) {
5119 cle->New(r);
5120 }
5121 }
5122 break;
5123
5124 } // switch etype
5125 } // for TIter next(fElements)
5126
5127 for(int nbase = 0; nbase < fNVirtualInfoLoc; ++nbase) {
5128 *(TStreamerInfo**)(p + fVirtualInfoLoc[nbase]) = this;
5129 }
5130 return p;
5131}
5132
5133////////////////////////////////////////////////////////////////////////////////
5134/// An array of emulated objects is created at address ary, if ary is null,
5135/// we allocate memory for the array.
5136
5138{
5139 if (fClass == 0) {
5140 Error("NewArray", "TClass pointer is null!");
5141 return 0;
5142 }
5143
5144 Int_t size = fClass->Size();
5145
5146 char* p = (char*) ary;
5147
5148 if (!p) {
5149 Long_t len = nElements * size + sizeof(Long_t)*2;
5150 p = new char[len];
5151 memset(p, 0, len);
5152 }
5153
5154 // Store the array cookie
5155 Long_t* r = (Long_t*) p;
5156 r[0] = size;
5157 r[1] = nElements;
5158 char* dataBegin = (char*) &r[2];
5159
5160 // Do a placement new for each element.
5161 p = dataBegin;
5162 for (Long_t cnt = 0; cnt < nElements; ++cnt) {
5163 New(p);
5164 p += size;
5165 } // for nElements
5166
5167 return dataBegin;
5168}
5169
5170
5171#define DeleteBasicPointer(addr,element,name) \
5172 { \
5173 name **f = (name**)(addr); \
5174 int n = element->GetArrayLength() ? element->GetArrayLength() : 1;\
5175 for(int j=0;j<n;j++) { \
5176 delete [] f[j]; \
5177 f[j] = 0; \
5178 } \
5179 }
5180
5181////////////////////////////////////////////////////////////////////////////////
5182/// Internal part of the destructor.
5183/// Destruct each of the datamembers in the same order
5184/// as the implicit destructor would.
5185
5187{
5188 R__ASSERT(obj != 0);
5189
5190 char *p = (char*)obj;
5191
5193 //for (; ele; ele = (TStreamerElement*) next())
5194 for (Int_t elenum = nelements - 1; elenum >= 0; --elenum) {
5196 if (ele->GetOffset() == kMissing) continue;
5197 char* eaddr = p + ele->GetOffset();
5198
5199 Int_t etype = ele->GetNewType(); // in memory type
5200 if (etype == TStreamerInfo::kNoType)
5201 etype = ele->GetType();
5202
5203 switch(etype) {
5220 }
5221
5222 TClass *cle = ele->GetNewClass(); // in memory type
5223 if (!cle)
5224 cle = ele->GetClassPointer();
5225 if (!cle)
5226 continue;
5227
5228 if (etype == kObjectp || etype == kAnyp) {
5229 // Destroy an array of pre-allocated objects.
5230 Int_t len = ele->GetArrayLength();
5231 if (!len) {
5232 len = 1;
5233 }
5234 void** r = (void**) eaddr;
5235 for (Int_t j = len - 1; j >= 0; --j) {
5236 if (r[j]) {
5237 cle->Destructor(r[j]);
5238 r[j] = 0;
5239 }
5240 }
5241 }
5242
5243 if ((etype == kObjectP || etype == kAnyP || etype == kSTLp) && !ele->TestBit(TStreamerElement::kDoNotDelete)) {
5244 // Destroy an array of pointers to not-pre-allocated objects.
5245 Int_t len = ele->GetArrayLength();
5246 if (!len) {
5247 len = 1;
5248 }
5249 void** r = (void**) eaddr;
5250 for (Int_t j = len - 1; j >= 0; --j) {
5251 if (r[j]) {
5252 cle->Destructor(r[j]);
5253 r[j] = 0;
5254 }
5255 }
5256 }
5257
5258 if (etype == kBase) {
5259 if (cle->Property() & kIsAbstract) {
5260 TVirtualStreamerInfo *einfo = cle->GetStreamerInfoAbstractEmulated();
5261 if (einfo) einfo->Destructor(eaddr, kTRUE);
5262 } else {
5263 cle->Destructor(eaddr, kTRUE);
5264 }
5265 }
5266
5267 if (etype == kObject || etype == kAny ||
5268 etype == kTObject || etype == kTString || etype == kTNamed) {
5269 // A data member is destroyed, but not deleted.
5270 cle->Destructor(eaddr, kTRUE);
5271 }
5272
5273 if (etype == kSTL) {
5274 // A data member is destroyed, but not deleted.
5275 TVirtualCollectionProxy *pr = cle->GetCollectionProxy();
5276 if (!pr) {
5277 if (strcmp(ele->GetName(),"This")==0) {
5278 // missing information, avoid infinite loop
5279 // by doing nothing ....
5280 } else {
5281 cle->Destructor(eaddr, kTRUE);
5282 }
5283 } else {
5284 if (ele->TestBit(TStreamerElement::kDoNotDelete)) {
5285 TVirtualCollectionProxy::TPushPop env(cle->GetCollectionProxy(), eaddr); // used for both this 'clear' and the 'clear' inside destructor.
5286 cle->GetCollectionProxy()->Clear(); // empty the collection without deleting the pointer
5287 pr->Destructor(eaddr, kTRUE);
5288 } else {
5289 pr->Destructor(eaddr, kTRUE);
5290 }
5291 }
5292 }
5293
5294 if (etype == kObject + kOffsetL || etype == kAny + kOffsetL ||
5295 etype == kTObject + kOffsetL || etype == kTString + kOffsetL ||
5296 etype == kTNamed + kOffsetL || etype == kSTL + kOffsetL) {
5297 // For a data member which is an array of objects, we
5298 // destroy the objects, but do not delete them.
5299 Int_t len = ele->GetArrayLength();
5300 Int_t size = cle->Size();
5301 char* r = eaddr + (size * (len - 1));
5302 for (Int_t j = len - 1; j >= 0; --j, r -= size) {
5303 cle->Destructor(r, kTRUE);
5304 }
5305 }
5306 } // iter over elements
5307
5308 if (!dtorOnly) {
5309 delete[] p;
5310 }
5311}
5312
5313////////////////////////////////////////////////////////////////////////////////
5314/// Emulated destructor for this class.
5315///
5316/// An emulated object is destroyed at address p.
5317/// Destruct each of the datamembers in the same order
5318/// as the implicit destructor would.
5319
5321{
5322 // Do nothing if passed a null pointer.
5323 if (obj == 0) return;
5324
5325 char* p = (char*) obj;
5326
5327 if (!dtorOnly && fNVirtualInfoLoc) {
5328 // !dtorOnly is used to filter out the case where this is called for
5329 // a base class or embedded object of the outer most class.
5330 TStreamerInfo *allocator = *(TStreamerInfo**)(p + fVirtualInfoLoc[0]);
5331 if (allocator != this) {
5332
5334
5335 p -= baseoffset;
5336 allocator->DestructorImpl(p, kFALSE);
5337 return;
5338 }
5339 }
5341}
5342
5343////////////////////////////////////////////////////////////////////////////////
5344/// Destroy an array of emulated objects, with optional delete.
5345
5347{
5348 // Do nothing if passed a null pointer.
5349 if (ary == 0) return;
5350
5351 //???FIX ME: What about varying length arrays?
5352
5353 Long_t* r = (Long_t*) ary;
5354 Long_t arrayLen = r[-1];
5355 Long_t size = r[-2];
5356 char* memBegin = (char*) &r[-2];
5357
5358 char* p = ((char*) ary) + ((arrayLen - 1) * size);
5359 for (Long_t cnt = 0; cnt < arrayLen; ++cnt, p -= size) {
5360 // Destroy each element, but do not delete it.
5361 Destructor(p, kTRUE);
5362 } // for arrayItemSize
5363
5364 if (!dtorOnly) {
5365 delete[] memBegin;
5366 }
5367}
5368
5369////////////////////////////////////////////////////////////////////////////////
5370/// print value of element i in object at pointer
5371/// The function may be called in two ways:
5372/// -method1 len < 0
5373/// i is assumed to be the TStreamerElement number i in StreamerInfo
5374/// -method2 len >= 0
5375/// i is the type
5376/// address of variable is directly pointer.
5377/// len is the number of elements to be printed starting at pointer.
5378
5379void TStreamerInfo::PrintValue(const char *name, char *pointer, Int_t i, Int_t len, Int_t lenmax) const
5380{
5381 char *ladd;
5383 printf(" %-15s = ",name);
5384
5386 Int_t *count = 0;
5387 if (len >= 0) {
5388 ladd = pointer;
5389 atype = i;
5390 aleng = len;
5391 } else {
5392 if (i < 0) {
5393 if (pointer==0) {
5394 printf("NULL\n");
5395 } else {
5396 const static TClassRef stringClass("string");
5397 if (fClass == stringClass) {
5398 std::string *st = (std::string*)(pointer);
5399 printf("%s\n",st->c_str());
5400 } else if (fClass == TString::Class()) {
5401 TString *st = (TString*)(pointer);
5402 printf("%s\n",st->Data());
5403 } else {
5404 printf("(%s*)0x%zx\n",GetName(),(size_t)pointer);
5405 }
5406 }
5407 return;
5408 }
5409 ladd = pointer + fCompFull[i]->fOffset;
5410 atype = fCompFull[i]->fNewType;
5411 aleng = fCompFull[i]->fLength;
5412 aElement = (TStreamerElement*)fCompFull[i]->fElem;
5413 count = (Int_t*)(pointer+fCompFull[i]->fMethod);
5414 }
5415 if (aleng > lenmax) aleng = lenmax;
5416
5418 printf("\n");
5419}
5420
5421////////////////////////////////////////////////////////////////////////////////
5422/// Print value of element i in a TClonesArray.
5423
5425{
5426 if (!clones) {printf(" %-15s = \n",name); return;}
5427 printf(" %-15s = ",name);
5428 Int_t nc = clones->GetEntriesFast();
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*)clones->UncheckedAt(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/// Print value of element i in an STL container.
5448
5450{
5451 if (!cont) {printf(" %-15s = \n",name); return;}
5452 printf(" %-15s = ",name);
5453 Int_t nc = cont->Size();
5454 if (nc > lenmax) nc = lenmax;
5455
5458 int aleng = fCompFull[i]->fLength;
5459 if (aleng > lenmax) aleng = lenmax;
5460
5461 for (Int_t k=0;k < nc;k++) {
5462 char *pointer = (char*)cont->At(k);
5463 char *ladd = pointer+offset;
5464 Int_t *count = (Int_t*)(pointer+fCompFull[i]->fMethod);
5465 PrintValueAux(ladd,fCompFull[i]->fNewType,aElement, aleng, count);
5466 if (k < nc-1) printf(", ");
5467 }
5468 printf("\n");
5469}
5470
5471////////////////////////////////////////////////////////////////////////////////
5472/// Replace the TClass this streamerInfo is pointing to (belongs to)
5473
5475{
5476 if (newcl) {
5477 // This is mostly (but not only) for the artificial "This" streamerElement for an stl collection.
5479 }
5480 fClass = newcl;
5481}
5482
5483////////////////////////////////////////////////////////////////////////////////
5484/// Stream an object of class TStreamerInfo.
5485
5487{
5488 UInt_t R__s, R__c;
5489 if (R__b.IsReading()) {
5490 Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
5491 fOldVersion = R__v;
5492 if (R__v > 1) {
5493 //R__b.ReadClassBuffer(TStreamerInfo::Class(), this, R__v, R__s, R__c);
5494 R__b.ClassBegin(TStreamerInfo::Class(), R__v);
5495 R__b.ClassMember("TNamed");
5498 R__b.ClassMember("fCheckSum","UInt_t");
5499 R__b >> fCheckSum;
5500 R__b.ClassMember("fClassVersion","Int_t");
5503 R__b.ClassMember("fElements","TObjArray*");
5504 R__b >> fElements;
5505 R__b.ClassEnd(TStreamerInfo::Class());
5506 R__b.SetBufferOffset(R__s+R__c+sizeof(UInt_t));
5510
5511 if (R__b.GetParent() && R__b.GetVersionOwner() < 50000)
5512 {
5513 // In some older files, the type of the TStreamerElement was not
5514 // as we (now) expect.
5517 for (Int_t i = 0; i < nobjects; i++) {
5519 TStreamerElement *rel = 0;
5520 if ( el->IsA() == basic ) {
5521 switch (el->GetType()) {
5522 default: break; /* nothing */
5523 case TStreamerInfo::kObject: /*61*/
5524 rel = new TStreamerObject(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5525 break;
5526 case TStreamerInfo::kAny: /*62*/
5527 rel = new TStreamerObjectAny(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5528 break;
5529 case TStreamerInfo::kObjectp: /* 63 */
5530 rel = new TStreamerObjectPointer(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5531 break;
5532 case TStreamerInfo::kObjectP: /* 64 */
5533 rel = new TStreamerObjectPointer(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5534 break;
5535 case TStreamerInfo::kTString: /* 65 */
5536 rel = new TStreamerObject(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5537 break;
5538 }
5539 if (rel) {
5540 (*fElements)[i] = rel;
5541 delete el;
5542 }
5543 }
5544 }
5545 }
5546 return;
5547 }
5548 //====process old versions before automatic schema evolution
5551 R__b >> fCheckSum;
5554 R__b >> fElements;
5555 R__b.CheckByteCount(R__s, R__c, TStreamerInfo::IsA());
5556 } else {
5557 R__c = R__b.WriteVersion(TStreamerInfo::IsA(), kTRUE);
5558 R__b.ClassBegin(TStreamerInfo::Class());
5559 R__b.ClassMember("TNamed");
5561 R__b.ClassMember("fCheckSum","UInt_t");
5562 R__b << fCheckSum;
5563 R__b.ClassMember("fClassVersion","Int_t");
5565
5566 //------------------------------------------------------------------------
5567 // Stream only non-artificial streamer elements
5568 //////////////////////////////////////////////////////////////////////////
5569
5570 R__b.ClassMember("fElements","TObjArray*");
5571 {
5572 TObjArray elements(fElements->GetEntriesFast());
5575 for (Int_t i = 0; i < nobjects; i++) {
5577 if (el != 0 && (el->IsA() == TStreamerArtificial::Class() || el->TestBit(TStreamerElement::kRepeat))) {
5578 // skip
5579 } else if (el != 0 && (el->TestBit(TStreamerElement::kCache) && !el->TestBit(TStreamerElement::kWrite))) {
5580 // skip
5581 } else if (el != 0) {
5582 elements.AddLast(el);
5583 }
5584 }
5585 R__b.WriteObjectAny(&elements, TObjArray::Class(), kFALSE);
5586 }
5587 R__b.ClassEnd(TStreamerInfo::Class());
5588 R__b.SetByteCount(R__c, kTRUE);
5589 }
5590}
5591
5592////////////////////////////////////////////////////////////////////////////////
5593/// Mark the classindex of the current file as using this TStreamerInfo.
5594/// This function is deprecated and its functionality is now done by
5595/// the overloads of TBuffer::TagStreamerInfo.
5596
5598{
5599 if (file) {
5600 // If the value of the atomic is kFALSE (equal to expected), change its value
5601 // to kTRUE and return true. Leave it as it is otherwise and return false.
5602 static std::atomic<Bool_t> onlyonce(kFALSE);
5604 if (onlyonce.compare_exchange_strong(expected,kTRUE)) {
5605 Warning("TagFile","This function is deprecated, use TBuffer::TagStreamerInfo instead");
5606 }
5607 TArrayC *cindex = file->GetClassIndex();
5608 Int_t nindex = cindex->GetSize();
5610 Error("TagFile","StreamerInfo: %s number: %d out of range[0,%d] in file: %s",
5611 GetName(),fNumber,nindex,file->GetName());
5612 return;
5613 }
5614 if (cindex->fArray[fNumber] == 0) {
5615 cindex->fArray[0] = 1;
5616 cindex->fArray[fNumber] = 1;
5617 }
5618 }
5619}
5620
5621////////////////////////////////////////////////////////////////////////////////
5622
5623#ifdef DOLOOP
5624#undef DOLOOP
5625#endif
5626#define DOLOOP for (k = 0, pointer = arr[0]; k < narr; pointer = arr[++k])
5627
5628namespace {
5629 static void PrintCR(int j,Int_t aleng, UInt_t ltype)
5630 {
5631 if (j == aleng-1) printf("\n");
5632 else {
5633 printf(", ");
5634 if (j%ltype == ltype-1) printf("\n ");
5635 }
5636 }
5637}
5638
5639////////////////////////////////////////////////////////////////////////////////
5640/// print value of element in object at pointer, type atype, leng aleng or *count
5641/// The function may be called in two ways:
5642/// -method1 len < 0
5643/// i is assumed to be the TStreamerElement number i in StreamerInfo
5644/// -method2 len >= 0
5645/// i is the type
5646/// address of variable is directly pointer.
5647/// len is the number of elements to be printed starting at pointer.
5648
5650{
5651 int j;
5652
5653 //assert(!((kOffsetP + kChar) <= atype && atype <= (kOffsetP + kBool) && count == 0));
5654 switch (atype) {
5655 // basic types
5656 case kBool: {Bool_t *val = (Bool_t* )ladd; printf("%d" ,*val); break;}
5657 case kChar: {Char_t *val = (Char_t* )ladd; printf("%d" ,*val); break;}
5658 case kShort: {Short_t *val = (Short_t* )ladd; printf("%d" ,*val); break;}
5659 case kInt: {Int_t *val = (Int_t* )ladd; printf("%d" ,*val); break;}
5660 case kLong: {Long_t *val = (Long_t* )ladd; printf("%ld",*val); break;}
5661 case kLong64: {Long64_t *val = (Long64_t* )ladd; printf("%lld",*val); break;}
5662 case kFloat: {Float_t *val = (Float_t* )ladd; printf("%f" ,*val); break;}
5663 case kFloat16: {Float_t *val = (Float_t* )ladd; printf("%f" ,*val); break;}
5664 case kDouble: {Double_t *val = (Double_t* )ladd; printf("%g" ,*val); break;}
5665 case kDouble32: {Double_t *val = (Double_t* )ladd; printf("%g" ,*val); break;}
5666 case kUChar: {UChar_t *val = (UChar_t* )ladd; printf("%u" ,*val); break;}
5667 case kUShort: {UShort_t *val = (UShort_t* )ladd; printf("%u" ,*val); break;}
5668 case kUInt: {UInt_t *val = (UInt_t* )ladd; printf("%u" ,*val); break;}
5669 case kULong: {ULong_t *val = (ULong_t* )ladd; printf("%lu",*val); break;}
5670 case kULong64: {ULong64_t *val = (ULong64_t*)ladd; printf("%llu",*val); break;}
5671 case kBits: {UInt_t *val = (UInt_t* )ladd; printf("%d" ,*val); break;}
5672
5673 // array of basic types array[8]
5674 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;}
5675 case kOffsetL + kChar: {Char_t *val = (Char_t* )ladd; for(j=0;j<aleng;j++) { printf("%c " ,val[j]); PrintCR(j,aleng,20); } break;}
5676 case kOffsetL + kShort: {Short_t *val = (Short_t* )ladd; for(j=0;j<aleng;j++) { printf("%d " ,val[j]); PrintCR(j,aleng,10); } break;}
5677 case kOffsetL + kInt: {Int_t *val = (Int_t* )ladd; for(j=0;j<aleng;j++) { printf("%d " ,val[j]); PrintCR(j,aleng,10); } break;}
5678 case kOffsetL + kLong: {Long_t *val = (Long_t* )ladd; for(j=0;j<aleng;j++) { printf("%ld ",val[j]); PrintCR(j,aleng, 5); } break;}
5679 case kOffsetL + kLong64: {Long64_t *val = (Long64_t* )ladd; for(j=0;j<aleng;j++) { printf("%lld ",val[j]);PrintCR(j,aleng, 5); } break;}
5680 case kOffsetL + kFloat: {Float_t *val = (Float_t* )ladd; for(j=0;j<aleng;j++) { printf("%f " ,val[j]); PrintCR(j,aleng, 5); } break;}
5681 case kOffsetL + kFloat16: {Float_t *val = (Float_t* )ladd; for(j=0;j<aleng;j++) { printf("%f " ,val[j]); PrintCR(j,aleng, 5); } break;}
5682 case kOffsetL + kDouble: {Double_t *val = (Double_t* )ladd; for(j=0;j<aleng;j++) { printf("%g " ,val[j]); PrintCR(j,aleng, 5); } break;}
5683 case kOffsetL + kDouble32:{Double_t *val = (Double_t* )ladd; for(j=0;j<aleng;j++) { printf("%g " ,val[j]); PrintCR(j,aleng, 5); } break;}
5684 case kOffsetL + kUChar: {UChar_t *val = (UChar_t* )ladd; for(j=0;j<aleng;j++) { printf("%u " ,val[j]); PrintCR(j,aleng,20); } break;}
5685 case kOffsetL + kUShort: {UShort_t *val = (UShort_t* )ladd; for(j=0;j<aleng;j++) { printf("%u " ,val[j]); PrintCR(j,aleng,10); } break;}
5686 case kOffsetL + kUInt: {UInt_t *val = (UInt_t* )ladd; for(j=0;j<aleng;j++) { printf("%u " ,val[j]); PrintCR(j,aleng, 5); } break;}
5687 case kOffsetL + kULong: {ULong_t *val = (ULong_t* )ladd; for(j=0;j<aleng;j++) { printf("%lu ",val[j]); PrintCR(j,aleng, 5); } break;}
5688 case kOffsetL + kULong64: {ULong64_t *val = (ULong64_t*)ladd; for(j=0;j<aleng;j++) { printf("%llu ",val[j]);PrintCR(j,aleng, 5); } break;}
5689 case kOffsetL + kBits: {UInt_t *val = (UInt_t* )ladd; for(j=0;j<aleng;j++) { printf("%d " ,val[j]); PrintCR(j,aleng, 5); } break;}
5690
5691 // pointer to an array of basic types array[n]
5692 case kOffsetP + kBool: {Bool_t **val = (Bool_t** )ladd; for(j=0;j<*count;j++) { printf("%d " ,(*val)[j]); PrintCR(j,aleng,20); } break;}
5693 case kOffsetP + kChar: {Char_t **val = (Char_t** )ladd; for(j=0;j<*count;j++) { printf("%d " ,(*val)[j]); PrintCR(j,aleng,20); } break;}
5694 case kOffsetP + kShort: {Short_t **val = (Short_t** )ladd; for(j=0;j<*count;j++) { printf("%d " ,(*val)[j]); PrintCR(j,aleng,10); } break;}
5695 case kOffsetP + kInt: {Int_t **val = (Int_t** )ladd; for(j=0;j<*count;j++) { printf("%d " ,(*val)[j]); PrintCR(j,aleng,10); } break;}
5696 case kOffsetP + kLong: {Long_t **val = (Long_t** )ladd; for(j=0;j<*count;j++) { printf("%ld ",(*val)[j]); PrintCR(j,aleng, 5); } break;}
5697 case kOffsetP + kLong64: {Long64_t **val = (Long64_t**)ladd; for(j=0;j<*count;j++) { printf("%lld ",(*val)[j]); PrintCR(j,aleng, 5); } break;}
5698 case kOffsetP + kFloat: {Float_t **val = (Float_t** )ladd; for(j=0;j<*count;j++) { printf("%f " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5699 case kOffsetP + kFloat16: {Float_t **val = (Float_t** )ladd; for(j=0;j<*count;j++) { printf("%f " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5700 case kOffsetP + kDouble: {Double_t **val = (Double_t**)ladd; for(j=0;j<*count;j++) { printf("%g " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5701 case kOffsetP + kDouble32:{Double_t **val = (Double_t**)ladd; for(j=0;j<*count;j++) { printf("%g " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5702 case kOffsetP + kUChar: {UChar_t **val = (UChar_t** )ladd; for(j=0;j<*count;j++) { printf("%u " ,(*val)[j]); PrintCR(j,aleng,20); } break;}
5703 case kOffsetP + kUShort: {UShort_t **val = (UShort_t**)ladd; for(j=0;j<*count;j++) { printf("%u " ,(*val)[j]); PrintCR(j,aleng,10); } break;}
5704 case kOffsetP + kUInt: {UInt_t **val = (UInt_t** )ladd; for(j=0;j<*count;j++) { printf("%u " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5705 case kOffsetP + kULong: {ULong_t **val = (ULong_t** )ladd; for(j=0;j<*count;j++) { printf("%lu ",(*val)[j]); PrintCR(j,aleng, 5); } break;}
5706 case kOffsetP + kULong64: {ULong64_t**val = (ULong64_t**)ladd; for(j=0;j<*count;j++){ printf("%llu ",(*val)[j]); PrintCR(j,aleng, 5); } break;}
5707
5708 // array counter //[n]
5709 case kCounter: {Int_t *val = (Int_t*)ladd; printf("%d",*val); break;}
5710 // char *
5711 case kCharStar:{
5712 char **val = (char**)ladd;
5713 if (*val) printf("%s",*val);
5714 break;
5715 }
5716 // Class * derived from TObject with comment field //->
5717 case kObjectp: {
5718 TObject **obj = (TObject**)(ladd);
5720 printf("(%s*)%zx",el ? el->GetClass()->GetName() : "unknown_type",(size_t)(*obj));
5721 break;
5722 }
5723
5724 // Class* derived from TObject
5725 case kObjectP: {
5726 TObject **obj = (TObject**)(ladd);
5728 printf("(%s*)%zx",el ? el->GetClass()->GetName() : "unknown_type",(size_t)(*obj));
5729 break;
5730 }
5731
5732 // Class derived from TObject
5733 case kObject: {
5734 TObject *obj = (TObject*)(ladd);
5735 printf("%s",obj->GetName());
5736 break;
5737 }
5738
5739 // Special case for TString, TObject, TNamed
5740 case kTString: {
5741 TString *st = (TString*)(ladd);
5742 printf("%s",st->Data());
5743 break;
5744 }
5745 case kTObject: {
5746 TObject *obj = (TObject*)(ladd);
5747 printf("%s",obj->GetName());
5748 break;
5749 }
5750 case kTNamed: {
5751 TNamed *named = (TNamed*) (ladd);
5752 printf("%s/%s",named->GetName(),named->GetTitle());
5753 break;
5754 }
5755
5756 // Class * not derived from TObject with comment field //->
5757 case kAnyp: {
5758 TObject **obj = (TObject**)(ladd);
5760 printf("(%s*)0x%zx",el ? el->GetClass()->GetName() : "unknown_type",(size_t)(*obj));
5761 break;
5762 }
5763
5764 // Class* not derived from TObject
5765 case kAnyP: {
5766 TObject **obj = (TObject**)(ladd);
5768 printf("(%s*)0x%zx",el ? el->GetClass()->GetName() : "unknown_type",(size_t)(*obj));
5769 break;
5770 }
5771 // Any Class not derived from TObject
5772 case kOffsetL + kObjectp:
5773 case kOffsetL + kObjectP:
5774 case kAny: {
5775 printf("printing kAny case (%d)",atype);
5776// if (aElement) {
5777// TMemberStreamer *pstreamer = aElement->GetStreamer();
5778// if (pstreamer == 0) {
5779// //printf("ERROR, Streamer is null\n");
5780// //aElement->ls();
5781// break;
5782// }
5783// //(*pstreamer)(b,ladd,0);
5784// }
5785 break;
5786 }
5787 // Base Class
5788 case kBase: {
5789 printf("printing kBase case (%d)",atype);
5790 //aElement->ReadBuffer(b,pointer);
5791 break;
5792 }
5793
5794 case kOffsetL + kObject:
5795 case kOffsetL + kTString:
5796 case kOffsetL + kTObject:
5797 case kOffsetL + kTNamed:
5798 case kStreamer: {
5799 printf("printing kStreamer case (%d)",atype);
5800// TMemberStreamer *pstreamer = aElement->GetStreamer();
5801// if (pstreamer == 0) {
5802// //printf("ERROR, Streamer is null\n");
5803// //aElement->ls();
5804// break;
5805// }
5806// //UInt_t start,count;
5807// //b.ReadVersion(&start, &count);
5808// //(*pstreamer)(b,ladd,0);
5809// //b.CheckByteCount(start,count,IsA());
5810 break;
5811 }
5812
5813 case kStreamLoop: {
5814 printf("printing kStreamLoop case (%d)",atype);
5815// TMemberStreamer *pstreamer = aElement->GetStreamer();
5816// if (pstreamer == 0) {
5817// //printf("ERROR, Streamer is null\n");
5818// //aElement->ls();
5819// break;
5820// }
5821 //Int_t *counter = (Int_t*)(count);
5822 //UInt_t start,count;
5823 ///b.ReadVersion(&start, &count);
5824 //(*pstreamer)(b,ladd,*counter);
5825 //b.CheckByteCount(start,count,IsA());
5826 break;
5827 }
5828 case kSTL: {
5829 if (aElement) {
5830 static TClassRef stringClass("string");
5831 if (ladd && aElement->GetClass() == stringClass) {
5832 std::string *st = (std::string*)(ladd);
5833 printf("%s",st->c_str());
5834 } else {
5835 printf("(%s*)0x%zx",aElement->GetClass()->GetName(),(size_t)(ladd));
5836 }
5837 } else {
5838 printf("(unknown_type*)0x%zx",(size_t)(ladd));
5839 }
5840 break;
5841 }
5842 }
5843}
5844
5845////////////////////////////////////////////////////////////////////////////////
5846///function called by the TClass constructor when replacing an emulated class
5847///by the real class
5848
5850{
5853 while ((element = (TStreamerElement*)nextElement())) {
5854 element->Update(oldcl,newcl);
5855 }
5856 for (Int_t i=0;i < fNslots;i++) {
5857 fComp[i].Update(oldcl,newcl);
5858 }
5859}
5860
5861////////////////////////////////////////////////////////////////////////////////
5862/// Update the TClass pointer cached in this object.
5863
5865{
5866 if (fType != -1) {
5867 if (fClass == oldcl || strcmp(fClassName, newcl->GetName()) == 0)
5868 fClass = newcl;
5869 else if (fClass == 0 && TClassTable::GetDict(fClassName))
5871 }
5872}
5873
5874////////////////////////////////////////////////////////////////////////////////
5875/// Generate emulated collection proxy for a given class.
5876
5882
5883////////////////////////////////////////////////////////////////////////////////
5884/// Generate emulated class streamer for a given collection class.
5885
5891
5892////////////////////////////////////////////////////////////////////////////////
5893/// Generate proxy from static functions.
5894
5896TStreamerInfo::GenExplicitProxy( const ::ROOT::TCollectionProxyInfo &info, TClass *cl )
5897{
5899}
5900
5901////////////////////////////////////////////////////////////////////////////////
5902/// Generate class streamer from static functions.
5903
5905TStreamerInfo::GenExplicitClassStreamer( const ::ROOT::TCollectionProxyInfo &info, TClass *cl )
5906{
5908}
5909
5910//
5911// Utility functions
5912//
5913static TStreamerElement* R__CreateEmulatedElement(const char *dmName, const std::string &dmFull, Int_t offset, bool silent)
5914{
5915 // Create a TStreamerElement for the type 'dmFull' and whose data member name is 'dmName'.
5916
5917 TString s1( TClassEdit::ShortType(dmFull.c_str(),0) );
5919 Bool_t dmIsPtr = (s1 != dmType);
5920 const char *dmTitle = "Emulation";
5921
5922 TDataType *dt = gROOT->GetType(dmType);
5923 if (dt && dt->GetType() > 0 ) { // found a basic type
5925 dtype = dt->GetType();
5926 dsize = dt->Size();
5927 if (dmIsPtr && dtype != kCharStar) {
5928 if (!silent)
5929 Error("Pair Emulation Building","%s is not yet supported in pair emulation",
5930 dmFull.c_str());
5931 return 0;
5932 } else {
5934 el->SetSize(dsize);
5935 return el;
5936 }
5937 } else {
5938
5939 static const char *full_string_name = "basic_string<char,char_traits<char>,allocator<char> >";
5940 if (strcmp(dmType,"string") == 0 || strcmp(dmType,"std::string") == 0 || strcmp(dmType,full_string_name)==0 ) {
5942 }
5944 return new TStreamerSTL(dmName,dmTitle,offset,dmFull.c_str(),dmFull.c_str(),dmIsPtr);
5945 }
5947 if (!clm) {
5949 if (enumdesc) {
5950 auto dtype = enumdesc->GetUnderlyingType();
5951 auto el = new TStreamerBasicType(dmName, dmTitle, offset, dtype, dmFull.c_str());
5953 if (datatype)
5954 el->SetSize(datatype->Size());
5955 else
5956 el->SetSize(sizeof(int)); // Default size of enums.
5957 return el;
5958 }
5959 return nullptr;
5960 }
5961 if (clm->GetState() <= TClass::kForwardDeclared)
5962 return nullptr;
5963 // a pointer to a class
5964 if ( dmIsPtr ) {
5965 if (clm->IsTObject()) {
5967 } else {
5969 }
5970 }
5971 // a class
5972 if (clm->IsTObject()) {
5973 return new TStreamerObject(dmName,dmTitle,offset,dmFull.c_str());
5974 } else if(clm == TString::Class() && !dmIsPtr) {
5976 } else {
5977 return new TStreamerObjectAny(dmName,dmTitle,offset,dmFull.c_str());
5978 }
5979 }
5980}
5981
5982/// \brief Generate the TClass and TStreamerInfo for the requested pair.
5983/// This creates a TVirtualStreamerInfo for the pair and trigger the BuildCheck/Old to
5984/// provoke the creation of the corresponding TClass. This relies on the dictionary for
5985/// std::pair<const int, int> to already exist (or the interpreter information being available)
5986/// as it is used as a template.
5987/// \note The returned object is owned by the caller.
5989{
5990 // Generate a TStreamerInfo for a std::pair<fname,sname>
5991 // This TStreamerInfo is then used as if it was read from a file to generate
5992 // and emulated TClass.
5993
5995 const char *msg = "problematic";
5997 msg = "the same";
5998 else if (hint_pair_offset > hint_pair_size) {
5999 if (hint_pair_size == 0)
6000 msg = "not specified";
6001 else
6002 msg = "smaller";
6003 }
6004 Error("GenerateInfoForPair",
6005 "Called with inconsistent offset and size. For \"std::pair<%s,%s>\" the requested offset is %ld but the size is %s (%ld)",
6006 firstname.c_str(), secondname.c_str(), (long)hint_pair_offset, msg, (long)hint_pair_offset);
6007 return nullptr;
6008 }
6009 TStreamerInfo *i = (TStreamerInfo*)TClass::GetClass("pair<const int,int>")->GetStreamerInfo()->Clone();
6010 std::string pname = "pair<" + firstname + "," + secondname;
6011 pname += (pname[pname.length()-1]=='>') ? " >" : ">";
6012 i->SetName(pname.c_str());
6013 i->SetClass(nullptr);
6014 i->GetElements()->Delete();
6016 Int_t size = 0;
6017 if (fel) {
6018 i->GetElements()->Add( fel );
6019
6020 size = fel->GetSize();
6021 Int_t sp = sizeof(void *);
6022 //align the non-basic data types (required on alpha and IRIX!!)
6023 if (size%sp != 0) size = size - size%sp + sp;
6024 } else {
6025 delete i;
6026 return 0;
6027 }
6028 if (hint_pair_offset)
6031 if (second) {
6032 i->GetElements()->Add( second );
6033 } else {
6034 delete i;
6035 return 0;
6036 }
6038 // Hide the warning about the missing pair dictionary.
6040 i->BuildCheck(nullptr, kFALSE); // Skipping the loading part (it would leads to infinite recursion on this very routine)
6042 if (i->TestBit(kCanDelete)) {
6043 // The StreamerInfo was deemed to be a duplicated (most likely case is
6044 // that we have the interpreter information already loaded for the
6045 // pair), so we need to delete it and return the one we already have.
6046 auto cl = i->GetClass();
6047 delete i;
6048 return cl->GetStreamerInfo();
6049 }
6050
6051 // In the state emulated, BuildOld would recalculate the offset and undo the offset update.
6052 // Note: we should consider adding a new state just for this (the hints indicates that we are mapping a compiled class but
6053 // then we would have to investigate all use of the state with <= and >= condition to make sure they are still appropriate).
6054 if (hint_pair_size) {
6057 }
6058
6059 i->BuildOld();
6060
6061 if (hint_pair_size)
6063 return i;
6064}
6065
6067{
6068 const static int pairlen = std::char_traits<char>::length("pair<");
6069 if (pairclassname.compare(0, pairlen, "pair<") != 0) {
6070 if (!silent)
6071 Error("GenerateInfoForPair", "The class name passed is not a pair: %s", pairclassname.c_str());
6072 return nullptr;
6073 }
6074
6075 std::vector<std::string> inside;
6076 int nested = 0;
6077 int num = TClassEdit::GetSplit(pairclassname.c_str(), inside, nested);
6078 if (num != 4) {
6079 if (!silent)
6080 Error("GenerateInfoForPair", "Could not find the pair arguments in %s", pairclassname.c_str());
6081 return nullptr;
6082 }
6083
6084 return GenerateInfoForPair(inside[1], inside[2], silent, hint_pair_offset, hint_pair_size);
6085}
#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
Boolean (0=false, 1=true) (bool)
Definition RtypesCore.h:77
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:59
short Version_t
Class version identifier (short)
Definition RtypesCore.h:79
char Char_t
Character 1 byte (char)
Definition RtypesCore.h:51
unsigned long ULong_t
Unsigned long integer 4 bytes (unsigned long). Size depends on architecture.
Definition RtypesCore.h:69
long Long_t
Signed long integer 4 bytes (long). Size depends on architecture.
Definition RtypesCore.h:68
unsigned int UInt_t
Unsigned integer 4 bytes (unsigned int)
Definition RtypesCore.h:60
float Float_t
Float 4 bytes (float)
Definition RtypesCore.h:71
short Short_t
Signed Short integer 2 bytes (short)
Definition RtypesCore.h:53
constexpr Bool_t kFALSE
Definition RtypesCore.h:108
double Double_t
Double 8 bytes.
Definition RtypesCore.h:73
long double LongDouble_t
Long Double (not portable)
Definition RtypesCore.h:75
long long Long64_t
Portable signed long integer 8 bytes.
Definition RtypesCore.h:83
constexpr Bool_t kTRUE
Definition RtypesCore.h:107
const char Option_t
Option string (const char)
Definition RtypesCore.h:80
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:385
#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:208
Int_t gErrorIgnoreLevel
errors with level below this value will be ignored. Default is kUnset.
Definition TError.cxx:33
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
Global variable setting the debug level. Set to 0 to disable, increase it in steps of 1 to increase t...
Definition TROOT.cxx:627
#define gROOT
Definition TROOT.h:411
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:2509
R__EXTERN TSystem * gSystem
Definition TSystem.h:572
#define R__LOCKGUARD(mutex)
#define snprintf
Definition civetweb.c:1579
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:29
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:6553
Bool_t IsSyntheticPair() const
Definition TClass.h:534
TDataMember * GetDataMember(const char *datamember) const
Return pointer to datamember object with name "datamember".
Definition TClass.cxx:3470
EState GetState() const
Definition TClass.h:501
ROOT::ESTLType GetCollectionType() const
Return the 'type' of the STL the TClass is representing.
Definition TClass.cxx:2891
void RemoveStreamerInfo(Int_t slot)
Remove and delete the StreamerInfo in the given slot.
Definition TClass.cxx:7417
Bool_t HasDataMemberInfo() const
Definition TClass.h:418
void CopyCollectionProxy(const TVirtualCollectionProxy &)
Replaces the collection proxy for this class.
Definition TClass.cxx:2475
Bool_t fIsSyntheticPair
Indicates whether this class can be split or not. Values are -1, 0, 1, 2.
Definition TClass.h:257
void RegisterStreamerInfo(TVirtualStreamerInfo *info)
Register the StreamerInfo in the given slot, change the State of the TClass as appropriate.
Definition TClass.cxx:7393
TVirtualStreamerInfo * GetCurrentStreamerInfo()
Definition TClass.h:451
void IgnoreTObjectStreamer(Bool_t ignore=kTRUE)
When the class kIgnoreTObjectStreamer bit is set, the automatically generated Streamer will not call ...
Definition TClass.cxx:4868
TClass * GetBaseClass(const char *classname)
Return pointer to the base class "classname".
Definition TClass.cxx:2660
Longptr_t GetDataMemberOffset(const char *membername) const
return offset for member name.
Definition TClass.cxx:3508
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:6542
Bool_t HasInterpreterInfo() const
Definition TClass.h:422
void BuildRealData(void *pointer=nullptr, Bool_t isTransient=kFALSE)
Build a full list of persistent data members.
Definition TClass.cxx:2036
TList * GetListOfDataMembers(Bool_t load=kTRUE)
Return list containing the TDataMembers of a class.
Definition TClass.cxx:3797
TList * GetListOfRealData() const
Definition TClass.h:465
Int_t Size() const
Return size of object of this class.
Definition TClass.cxx:5743
Bool_t CanIgnoreTObjectStreamer()
Definition TClass.h:404
const ROOT::Detail::TSchemaRuleSet * GetSchemaRules() const
Return the set of the schema rules if any.
Definition TClass.cxx:1932
TList * GetListOfBases()
Return list containing the TBaseClass(es) of a class.
Definition TClass.cxx:3663
const TObjArray * GetStreamerInfos() const
Definition TClass.h:505
Bool_t IsLoaded() const
Return true if the shared library of this class is currently in the a process's memory.
Definition TClass.cxx:5954
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition TClass.cxx:5980
Bool_t IsForeign() const
Return kTRUE is the class is Foreign (the class does not have a Streamer method).
Definition TClass.cxx:5989
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:4626
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:2796
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition TClass.cxx:2902
Int_t GetClassSize() const
Definition TClass.h:437
Long_t Property() const override
Returns the properties of the TClass as a bit field stored as a Long_t value.
Definition TClass.cxx:6128
@ 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:535
void SetClassSize(Int_t sizof)
Definition TClass.h:315
Version_t GetClassVersion() const
Definition TClass.h:432
TRealData * GetRealData(const char *name) const
Return pointer to TRealData element with name "name".
Definition TClass.cxx:3534
@ 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:2973
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.
Bool_t IsEnum() const
Return true if data member is an enum.
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:181
@ kNone
Definition TEnum.h:49
A ROOT file is an on-disk file, usually with extension .root, that stores objects in a file-system-li...
Definition TFile.h:131
const TList * GetStreamerInfoCache()
Returns the cached list of StreamerInfos used in this file.
Definition TFile.cxx:1355
Int_t GetVersion() const
Definition TFile.h:324
TArrayC * GetClassIndex() const
Definition TFile.h:305
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:575
static TString GetHeaderName(const char *name, const TList *extrainfos, Bool_t includeNested=kFALSE)
Return the header name containing the description of name.
static UInt_t GenerateForwardDeclaration(FILE *fp, const char *clname, char *inclist, Bool_t implementEmptyClass, Bool_t needGenericTemplate, const TList *extrainfos)
Insert a (complete) forward declaration for the class 'clname'.
static void AddInclude(FILE *fp, const char *header, Bool_t system, char *inclist)
Add an include statement, if it has not already been added.
static UInt_t GenerateIncludeForTemplate(FILE *fp, const char *clname, char *inclist, Bool_t forward, const TList *extrainfos)
Add to the header file, the #include needed for the argument of this template.
static void GeneratePostDeclaration(FILE *fp, const TVirtualStreamerInfo *info, char *inclist)
Add to the header file anything that need to appear after the class declaration (this includes some #...
static UInt_t GenerateClassPrefix(FILE *fp, const char *clname, Bool_t top, TString &protoname, UInt_t *numberOfClasses, Int_t implementEmptyClass=kFALSE, Bool_t needGenericTemplate=kFALSE)
Write the start of the class (forward) declaration.
static TString UpdateAssociativeToVector(const char *name)
Abstract base class for accessing the data-members of a class.
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:73
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
void Streamer(TBuffer &) override
Stream an object of class TObject.
const char * GetTitle() const override
Returns title of object.
Definition TNamed.h:50
TString fName
Definition TNamed.h:32
static TClass * Class()
virtual void SetName(const char *name)
Set the name of the TNamed.
Definition TNamed.cxx:149
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:243
virtual const char * GetName() const
Returns name of object.
Definition TObject.cxx:457
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition TObject.h:202
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:1057
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:864
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1071
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition TObject.cxx:1099
virtual void ls(Option_t *option="") const
The ls function lists the contents of a class on stdout.
Definition TObject.cxx:592
void ResetBit(UInt_t f)
Definition TObject.h:201
@ kNoContextMenu
if object does not want context menu
Definition TObject.h:75
@ kCanDelete
if object in a list can be deleted
Definition TObject.h:68
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition TObject.cxx:1045
void Obsolete(const char *method, const char *asOfVers, const char *removedFromVers) const
Use this method to declare a method obsolete.
Definition TObject.cxx:1142
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()
Describe one element (data member) to be Streamed.
virtual TClass * GetClassPointer() const
Returns a pointer to the TClass of this element and updates fClassObject.
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 pointer to STL container and eventually element k i...
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 an STL container and eventually element k in a sub-ar...
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 an STL container.
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:138
void ToLower()
Change string to lower-case.
Definition TString.cxx:1189
void Clear()
Clear string without changing its capacity.
Definition TString.cxx:1241
const char * Data() const
Definition TString.h:384
@ kTrailing
Definition TString.h:284
TString & Append(const char *cs)
Definition TString.h:580
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:2384
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition TString.cxx:2362
static TClass * Class()
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:640
virtual const char * BaseName(const char *pathname)
Base name of a file name. Base name of /user/root is root.
Definition TSystem.cxx:944
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
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:230
bool IsStdClass(const char *type)
return true if the class belongs to the std namespace
bool IsStdPair(std::string_view name)
Definition TClassEdit.h:231
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:83
bool IsSTLBitset(const char *type)
Return true is the name is std::bitset<number> or bitset<number>