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