Logo ROOT  
Reference Guide
 
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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 if (fClassVersion > 1 || (cl && cl->IsTObject()) ) {
4087 // add 1 to class version in case we didn't manage reproduce the class layout to 100%.
4088 if (fClassVersion == 0) {
4089 // If the class was declared 'transient', keep it that way.
4090 fprintf(fp," ClassDef(%s,%d); // Generated by MakeProject.\n",protoname.Data(),0);
4091 } else {
4092 fprintf(fp," ClassDef(%s,%d); // Generated by MakeProject.\n",protoname.Data(),fClassVersion + 1);
4093 }
4094 }
4095 fprintf(fp,"};\n");
4096
4097 for(UInt_t i=0;i<numberOfNamespaces;++i) {
4098 fprintf(fp,"} // namespace\n");
4099 }
4100
4102 fprintf(fp,"#endif // generic template declaration\n");
4103 }
4104}
4105
4106////////////////////////////////////////////////////////////////////////////////
4107/// Add to the header file, the \#include need for this class.
4108
4110{
4111 if (inclist[0]==0) {
4112 // Always have this include for ClassDef.
4113 TMakeProject::AddInclude( fp, "Rtypes.h", kFALSE, inclist);
4114 }
4115 UInt_t ninc = 0;
4116
4117 const char *clname = GetName();
4118 if (strchr(clname,'<')) {
4119 // This is a template, we need to check the template parameter.
4121 }
4122
4123 TString name(1024);
4124 Int_t ltype = 10;
4125 Int_t ldata = 10;
4126 Int_t lt;
4127 Int_t ld;
4128 TIter next(fElements);
4131 while ((element = (TStreamerElement*)next())) {
4132 //if (element->IsA() == TStreamerBase::Class()) continue;
4133 const char *ename = element->GetName();
4134 const char *colon2 = strstr(ename,"::");
4135 if (colon2) ename = colon2+2;
4136 name = ename;
4137 for (Int_t i=0;i < element->GetArrayDim();i++) {
4138 name += TString::Format("[%d]",element->GetMaxIndex(i));
4139 }
4140 ld = name.Length();
4141 lt = strlen(element->GetTypeName());
4142 if (ltype < lt) ltype = lt;
4143 if (ldata < ld) ldata = ld;
4144
4145 //must include Riostream.h in case of an STL container
4146 if (!incRiostream && element->InheritsFrom(TStreamerSTL::Class())) {
4148 TMakeProject::AddInclude( fp, "Riostream.h", kFALSE, inclist);
4149 }
4150
4151 //get include file name if any
4152 const char *include = element->GetInclude();
4153 if (!include[0]) continue;
4154
4155 Bool_t greater = (include[0]=='<');
4156 include++;
4157
4158 if (strncmp(include,"include/",8)==0) {
4159 include += 8;
4160 }
4161 if (strncmp(include,"include\",9)==0) {
4162 include += 9;
4163 }
4164 if (TClassEdit::IsStdPair(element->GetTypeName())) {
4165 TMakeProject::AddInclude( fp, "utility", kTRUE, inclist);
4166 } else if (strncmp(element->GetTypeName(),"auto_ptr<",std::char_traits<char>::length("auto_ptr<"))==0) {
4167 TMakeProject::AddInclude( fp, "memory", kTRUE, inclist);
4168 } else {
4172 }
4173
4174 if (strchr(element->GetTypeName(),'<')) {
4175 // This is a template, we need to check the template parameter.
4177 }
4178 }
4179 return ninc;
4180}
4181
4182////////////////////////////////////////////////////////////////////////////////
4183/// Generate header file for the class described by this TStreamerInfo
4184/// the function is called by TFile::MakeProject for each class in the file
4185
4187{
4188 // if (fClassVersion == -4) return 0;
4189 if ((fClass && fClass->GetCollectionType()) || TClassEdit::IsSTLCont(GetName())) return 0;
4190 if (TClassEdit::IsStdPair(GetName())) return 0;
4191 if (strncmp(GetName(),"auto_ptr<",std::char_traits<char>::length("auto_ptr<"))==0) return 0;
4192
4194 if (cl) {
4195 if (cl->HasInterpreterInfo()) return 0; // skip known classes
4196 }
4198 if (strchr(GetName(),':')) {
4199 UInt_t len = strlen(GetName());
4200 UInt_t nest = 0;
4201 UInt_t scope = 0;
4202 for(UInt_t i=len; i>0; --i) {
4203 switch(GetName()[i]) {
4204 case '>': ++nest; if (scope==0) { isTemplate = kTRUE; } break;
4205 case '<': --nest; break;
4206 case ':':
4207 if (nest==0 && GetName()[i-1]==':') {
4208 // We have a scope
4209 TString nsname(GetName(), i-1);
4210 cl = gROOT->GetClass(nsname);
4211 if (cl && (cl->Size()!=0 || (cl->Size()==0 && !cl->HasInterpreterInfo() /*empty 'base' class on file*/))) {
4212 // This class is actually nested.
4213 return 0;
4214 } else if (cl == 0 && extrainfos != 0) {
4216 if (clinfo && clinfo->GetClassVersion() == -5) {
4217 // This class is actually nested.
4218 return 0;
4219 }
4220 }
4221 ++scope;
4222 }
4223 break;
4224 }
4225 }
4226 }
4228
4229 if (gDebug) printf("generating code for class %s\n",GetName());
4230
4231 // Open the file
4232
4235 filename.Form("%s/%s.h",dirname,headername.Data());
4236
4237 FILE *fp = fopen(filename.Data(),"w");
4238 if (!fp) {
4239 Error("MakeProject","Cannot open output file:%s\n",filename.Data());
4240 return 0;
4241 }
4242
4243 filename.Form("%s/%sProjectHeaders.h",dirname,gSystem->BaseName(dirname));
4244 FILE *allfp = fopen(filename.Data(),"a");
4245 if (!allfp) {
4246 Error("MakeProject","Cannot open output file:%s\n",filename.Data());
4247 fclose(fp);
4248 return 0;
4249 }
4250 fprintf(allfp,"#include \"%s.h\"\n", headername.Data());
4251 fclose(allfp);
4252
4253 char *inclist = new char[50000];
4254 inclist[0] = 0;
4255
4256 // Generate class header.
4257 TDatime td;
4258 fprintf(fp,"//////////////////////////////////////////////////////////\n");
4259 fprintf(fp,"// This class has been generated by TFile::MakeProject\n");
4260 fprintf(fp,"// (%s by ROOT version %s)\n",td.AsString(),gROOT->GetVersion());
4261 fprintf(fp,"// from the StreamerInfo in file %s\n",gDirectory->GetFile()->GetName());
4262 fprintf(fp,"//////////////////////////////////////////////////////////\n");
4263 fprintf(fp,"\n");
4264 fprintf(fp,"\n");
4265 fprintf(fp,"#ifndef %s_h\n",headername.Data());
4266 fprintf(fp,"#define %s_h\n",headername.Data());
4268 fprintf(fp,"\n");
4269
4271 if (subClasses) {
4274 while ((subinfo = (TStreamerInfo*)subnext())) {
4275 subinfo->GenerateIncludes(fp, inclist, extrainfos);
4276 }
4277 }
4278 fprintf(fp,"\n");
4279
4280 TString sourcename; sourcename.Form( "%s/%sProjectSource.cxx", dirname, gSystem->BaseName(dirname) );
4281 FILE *sfp = fopen( sourcename.Data(), "a" );
4282 if (sfp) {
4284 } else {
4285 Error("GenerateHeaderFile","Could not open %s for appending",sourcename.Data());
4286 }
4288
4289 fprintf(fp,"#endif\n");
4290
4291 delete [] inclist;
4292 fclose(fp);
4293 if (sfp) fclose(sfp);
4294 return 1;
4295}
4296
4297////////////////////////////////////////////////////////////////////////////////
4298/// Compute data member offset.
4299/// Return pointer to the Streamer function if one exists
4300
4302{
4304 char dmbracket[256];
4305 snprintf(dmbracket,255,"%s[",dm->GetName());
4307 if (!fClass->IsLoaded()) {
4308 // If the 'class' is not loaded, we do not have a TClass bootstrap and thus
4309 // the 'RealData' might not have enough information because of the lack
4310 // of proper ShowMember implementation.
4311 if (! (dm->Property() & kIsStatic) ) {
4312 // Give an offset only to non-static members.
4313 offset = dm->GetOffset();
4314 }
4315 }
4316 TRealData *rdm;
4317 while ((rdm = (TRealData*)nextr())) {
4318 char *rdmc = (char*)rdm->GetName();
4319 //next statement required in case a class and one of its parent class
4320 //have data members with the same name
4321 if (dm->IsaPointer() && rdmc[0] == '*') rdmc++;
4322
4323 if (rdm->GetDataMember() != dm) continue;
4324 if (strcmp(rdmc,dm->GetName()) == 0) {
4325 offset = rdm->GetThisOffset();
4326 streamer = rdm->GetStreamer();
4327 break;
4328 }
4329 if (strcmp(rdm->GetName(),dm->GetName()) == 0) {
4330 if (rdm->IsObject()) {
4331 offset = rdm->GetThisOffset();
4332 streamer = rdm->GetStreamer();
4333 break;
4334 }
4335 }
4336 if (strstr(rdm->GetName(),dmbracket)) {
4337 offset = rdm->GetThisOffset();
4338 streamer = rdm->GetStreamer();
4339 break;
4340 }
4341 }
4342 return offset;
4343}
4344
4345////////////////////////////////////////////////////////////////////////////////
4346/// Return the offset of the data member as indicated by this StreamerInfo.
4347
4349{
4350 if (elementName == 0) return 0;
4351
4352 Int_t offset = 0;
4354 if (elem) offset = elem->GetOffset();
4355
4356 return offset;
4357}
4358
4359////////////////////////////////////////////////////////////////////////////////
4360/// Return total size of all persistent elements of the class (with offsets).
4361
4363{
4364 return fSize;
4365}
4366
4367////////////////////////////////////////////////////////////////////////////////
4368/// Return total size of all persistent elements of the class
4369/// use GetSize if you want to get the real size in memory.
4370
4372{
4373 TIter next(fElements);
4375 Int_t asize = 0;
4376 while ((element = (TStreamerElement*)next())) {
4377 asize += element->GetSize();
4378 }
4379 return asize;
4380}
4381
4382////////////////////////////////////////////////////////////////////////////////
4383/// Return the StreamerElement of "datamember" inside our
4384/// class or any of its base classes.
4385///
4386/// The offset information
4387/// contained in the StreamerElement is related to its immediately
4388/// containing class, so we return in 'offset' the offset inside
4389/// our class.
4390
4392{
4393 if (!fElements) {
4394 return 0;
4395 }
4396
4397 // Look first at the data members and base classes
4398 // of our class.
4400 if (element) {
4401 offset = element->GetOffset();
4402 return element;
4403 }
4404
4405 // Not found, so now try the data members and base classes
4406 // of the base classes of our class.
4407 if (fClass->HasDataMemberInfo()) {
4408 // Our class has a dictionary loaded, use it to search the base classes.
4410 TBaseClass* base = 0;
4411 TClass* base_cl = 0;
4412 Int_t base_offset = 0;
4413 Int_t local_offset = 0;
4415 // Iterate on list of base classes.
4416 while ((base = (TBaseClass*) nextb())) {
4417 base_cl = TClass::GetClass(base->GetName());
4419 if (!base_cl || !base_element) {
4420 continue;
4421 }
4422 base_offset = base_element->GetOffset();
4424 if (element) {
4426 return element;
4427 }
4428 }
4429 } else {
4430 // Our class's dictionary is not loaded. Search through the base class streamer elements.
4431 TIter next(fElements);
4433 while ((curelem = (TStreamerElement*) next())) {
4434 if (curelem->InheritsFrom(TStreamerBase::Class())) {
4435 TClass* baseClass = curelem->GetClassPointer();
4436 if (!baseClass) {
4437 continue;
4438 }
4439 Int_t base_offset = curelem->GetOffset();
4440 Int_t local_offset = 0;
4442 if (baseClass->Property() & kIsAbstract) {
4443 baseInfo = (TStreamerInfo*)baseClass->GetStreamerInfoAbstractEmulated();
4444 } else {
4445 baseInfo = (TStreamerInfo*)baseClass->GetStreamerInfo();
4446 }
4447 if (baseInfo) element = baseInfo->GetStreamerElement(datamember, local_offset);
4448 if (element) {
4450 return element;
4451 }
4452 }
4453 }
4454 }
4455 return 0;
4456}
4457
4458////////////////////////////////////////////////////////////////////////////////
4459/// <b>Obsolete</b>: this routine is obsolete and should not longer be used.
4460///
4461/// TStreamerInfo holds two types of data structures
4462/// - TObjArray* fElements; containing the list of all TStreamerElement
4463/// objects for this class version.
4464/// - ULong_t* fElem; containing the preprocessed information
4465/// by TStreamerInfo::Compile In case consecutive data members
4466/// are of the same type, the Compile function declares the consecutive
4467/// elements as one single element in fElems.
4468///
4469/// Example with the class TAttLine:
4470/// ~~~{.cpp}
4471/// TClass::GetClass("TAttLine")->GetStreamerInfo()->ls(); produces;
4472/// StreamerInfo for class: TAttLine, version=1
4473/// short fLineColor offset= 4 type= 2 line color
4474/// short fLineStyle offset= 6 type= 2 line style
4475/// short fLineWidth offset= 8 type= 2 line width
4476/// i= 0, fLineColor type= 22, offset= 4, len=3, method=0
4477/// ~~~
4478/// For I/O implementations (eg. XML) , one has to know the original name
4479/// of the data member. This function can be used to return a pointer
4480/// to the original TStreamerElement object corresponding to the j-th
4481/// element of a compressed array in fElems.
4482/// Parameters description:
4483/// - i: the serial number in array fElem
4484/// - j: the element number in the array of consecutive types
4485/// In the above example the class TAttLine has 3 consecutive data members
4486/// of the same type "short". Compile makes one single array of 3 elements.
4487/// To access the TStreamerElement for the second element
4488/// of this array, one can call:
4489/// ~~~{.cpp}
4490/// auto el = GetStreamerElementReal(0,1);
4491/// auto membername = el->GetName();
4492/// ~~~
4493/// This function is typically called from TBuffer, TXmlBuffer.
4494
4496{
4497 ::Obsolete("TStreamerInfo::GetStreamerElementReal", "v5-34-20", "v6-00-02");
4498
4499 if (i < 0 || i >= fNdata) return 0;
4500 if (j < 0) return 0;
4501 if (!fElements) return 0;
4503 if (!se) return 0;
4505 for (Int_t ise=0;ise < nelems;ise++) {
4506 if (se != (TStreamerElement*)fElements->UncheckedAt(ise)) continue;
4507 if (ise+j >= nelems) return 0;
4509 }
4510 return 0;
4511}
4512
4513////////////////////////////////////////////////////////////////////////////////
4514/// Get the value from inside a collection.
4515
4516template <typename T>
4518{
4519 if (type>=kConv && type<kSTL) {
4520 type -= kConv;
4521 }
4522 switch (type) {
4523 // basic types
4524 case kBool: {Bool_t *val = (Bool_t*)ladd; return T(*val);}
4525 case kChar: {Char_t *val = (Char_t*)ladd; return T(*val);}
4526 case kShort: {Short_t *val = (Short_t*)ladd; return T(*val);}
4527 case kInt: {Int_t *val = (Int_t*)ladd; return T(*val);}
4528 case kLong: {Long_t *val = (Long_t*)ladd; return T(*val);}
4529 case kLong64: {Long64_t *val = (Long64_t*)ladd; return T(*val);}
4530 case kFloat: {Float_t *val = (Float_t*)ladd; return T(*val);}
4531 case kFloat16: {Float_t *val = (Float_t*)ladd; return T(*val);}
4532 case kDouble: {Double_t *val = (Double_t*)ladd; return T(*val);}
4533 case kDouble32: {Double_t *val = (Double_t*)ladd; return T(*val);}
4534 case kUChar: {UChar_t *val = (UChar_t*)ladd; return T(*val);}
4535 case kUShort: {UShort_t *val = (UShort_t*)ladd; return T(*val);}
4536 case kUInt: {UInt_t *val = (UInt_t*)ladd; return T(*val);}
4537 case kULong: {ULong_t *val = (ULong_t*)ladd; return T(*val);}
4538#if defined(_MSC_VER) && (_MSC_VER <= 1200)
4539 case kULong64: {Long64_t *val = (Long64_t*)ladd; return T(*val);}
4540#else
4541 case kULong64: {ULong64_t *val= (ULong64_t*)ladd; return T(*val);}
4542#endif
4543 case kBits: {UInt_t *val = (UInt_t*)ladd; return T(*val);}
4544
4545 // array of basic types array[8]
4546 case kOffsetL + kBool: {Bool_t *val = (Bool_t*)ladd; return T(val[k]);}
4547 case kOffsetL + kChar: {Char_t *val = (Char_t*)ladd; return T(val[k]);}
4548 case kOffsetL + kShort: {Short_t *val = (Short_t*)ladd; return T(val[k]);}
4549 case kOffsetL + kInt: {Int_t *val = (Int_t*)ladd; return T(val[k]);}
4550 case kOffsetL + kLong: {Long_t *val = (Long_t*)ladd; return T(val[k]);}
4551 case kOffsetL + kLong64: {Long64_t *val = (Long64_t*)ladd; return T(val[k]);}
4552 case kOffsetL + kFloat: {Float_t *val = (Float_t*)ladd; return T(val[k]);}
4553 case kOffsetL + kFloat16: {Float_t *val = (Float_t*)ladd; return T(val[k]);}
4554 case kOffsetL + kDouble: {Double_t *val = (Double_t*)ladd; return T(val[k]);}
4555 case kOffsetL + kDouble32:{Double_t *val = (Double_t*)ladd; return T(val[k]);}
4556 case kOffsetL + kUChar: {UChar_t *val = (UChar_t*)ladd; return T(val[k]);}
4557 case kOffsetL + kUShort: {UShort_t *val = (UShort_t*)ladd; return T(val[k]);}
4558 case kOffsetL + kUInt: {UInt_t *val = (UInt_t*)ladd; return T(val[k]);}
4559 case kOffsetL + kULong: {ULong_t *val = (ULong_t*)ladd; return T(val[k]);}
4560#if defined(_MSC_VER) && (_MSC_VER <= 1200)
4561 case kOffsetL + kULong64: {Long64_t *val = (Long64_t*)ladd; return T(val[k]);}
4562#else
4563 case kOffsetL + kULong64:{ULong64_t *val= (ULong64_t*)ladd; return T(val[k]);}
4564#endif
4565
4566#define READ_ARRAY(TYPE_t) \
4567 { \
4568 Int_t sub_instance, index; \
4569 Int_t instance = k; \
4570 if (len) { \
4571 index = instance / len; \
4572 sub_instance = instance % len; \
4573 } else { \
4574 index = instance; \
4575 sub_instance = 0; \
4576 } \
4577 TYPE_t **val =(TYPE_t**)(ladd); \
4578 return T((val[sub_instance])[index]); \
4579 }
4580
4581 // pointer to an array of basic types array[n]
4582 case (unsigned)kOffsetP + kBool_t: READ_ARRAY(Bool_t)
4583 case (unsigned)kOffsetP + kChar_t: READ_ARRAY(Char_t)
4584 case (unsigned)kOffsetP + kShort_t: READ_ARRAY(Short_t)
4585 case (unsigned)kOffsetP + kInt_t: READ_ARRAY(Int_t)
4586 case (unsigned)kOffsetP + kLong_t: READ_ARRAY(Long_t)
4587 case (unsigned)kOffsetP + kLong64_t: READ_ARRAY(Long64_t)
4588 case (unsigned)kOffsetP + kFloat16_t:
4589 case (unsigned)kOffsetP + kFloat_t: READ_ARRAY(Float_t)
4590 case (unsigned)kOffsetP + kDouble32_t:
4591 case (unsigned)kOffsetP + kDouble_t: READ_ARRAY(Double_t)
4592 case (unsigned)kOffsetP + kUChar_t: READ_ARRAY(UChar_t)
4593 case (unsigned)kOffsetP + kUShort_t: READ_ARRAY(UShort_t)
4594 case (unsigned)kOffsetP + kUInt_t: READ_ARRAY(UInt_t)
4595 case (unsigned)kOffsetP + kULong_t: READ_ARRAY(ULong_t)
4596#if defined(_MSC_VER) && (_MSC_VER <= 1200)
4597 case (unsigned)kOffsetP + kULong64_t: READ_ARRAY(Long64_t)
4598#else
4599 case (unsigned)kOffsetP + kULong64_t: READ_ARRAY(ULong64_t)
4600#endif
4601
4602 // array counter //[n]
4603 case kCounter: {Int_t *val = (Int_t*)ladd; return T(*val);}
4604 }
4605 return 0;
4606}
4607
4608
4609
4610template Double_t TStreamerInfo::GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const;
4611template Long64_t TStreamerInfo::GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const;
4612template LongDouble_t TStreamerInfo::GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const;
4613
4614////////////////////////////////////////////////////////////////////////////////
4615/// Return value of element i in object at pointer.
4616/// The function may be called in two ways:
4617/// - method1 len < 0: i is assumed to be the TStreamerElement number i in StreamerInfo
4618/// - method2 len >= 0: i is the type, address of variable is directly pointer.
4619
4620template <typename T>
4622{
4623 char *ladd;
4624 Int_t atype;
4625 if (len >= 0) {
4626 ladd = pointer;
4627 atype = i;
4628 } else {
4629 if (i < 0) return 0;
4630 ladd = pointer + fCompFull[i]->fOffset;
4631 atype = fCompFull[i]->fNewType;
4633 if (atype == kSTL) {
4635 if (newClass == 0) {
4637 }
4638 TClass *innerClass = newClass->GetCollectionProxy()->GetValueClass();
4639 if (innerClass) {
4640 return 0; // We don't know which member of the class we would want.
4641 } else {
4642 TVirtualCollectionProxy *proxy = newClass->GetCollectionProxy();
4643 // EDataType is a subset of TStreamerInfo::EReadWrite
4646 Int_t nc = proxy->Size();
4647 if (j >= nc) return 0;
4648 char *element_ptr = (char*)proxy->At(j);
4650 }
4651 }
4652 }
4654}
4655
4656////////////////////////////////////////////////////////////////////////////////
4657
4658template Double_t TStreamerInfo::GetTypedValueClones<Double_t>(TClonesArray *clones, Int_t i, Int_t j, int k, Int_t eoffset) const;
4661
4662template <typename T>
4664{
4665 // return value of element i in object number j in a TClonesArray and eventually
4666 // element k in a sub-array.
4667
4668 Int_t nc = clones->GetEntriesFast();
4669 if (j >= nc) return 0;
4670
4671 char *pointer = (char*)clones->UncheckedAt(j);
4672 char *ladd = pointer + eoffset + fCompFull[i]->fOffset;
4673 return GetTypedValueAux<T>(fCompFull[i]->fType,ladd,k,((TStreamerElement*)fCompFull[i]->fElem)->GetArrayLength());
4674}
4675
4679
4680////////////////////////////////////////////////////////////////////////////////
4681/// Return value of element i in object number j in a TClonesArray and eventually
4682/// element k in a sub-array.
4683
4684template <typename T>
4686{
4687 Int_t nc = cont->Size();
4688 if (j >= nc) return 0;
4689
4690 char *pointer = (char*)cont->At(j);
4691 char *ladd = pointer + eoffset + fCompFull[i]->fOffset;
4692 return GetTypedValueAux<T>(fCompFull[i]->fType,ladd,k,((TStreamerElement*)fCompFull[i]->fElem)->GetArrayLength());
4693}
4694
4698
4699////////////////////////////////////////////////////////////////////////////////
4700/// Return value of element i in object number j in a TClonesArray and eventually
4701/// element k in a sub-array.
4702
4703template <typename T>
4705{
4706 Int_t nc = cont->Size();
4707
4708 if (j >= nc) return 0;
4709
4710 char **ptr = (char**)cont->At(j);
4711 char *pointer = *ptr;
4712
4713 char *ladd = pointer + eoffset + fCompFull[i]->fOffset;
4714 return GetTypedValueAux<T>(fCompFull[i]->fType,ladd,k,((TStreamerElement*)fCompFull[i]->fElem)->GetArrayLength());
4715}
4716
4717////////////////////////////////////////////////////////////////////////////////
4718/// Insert new members as expressed in the array of TSchemaRule(s).
4719
4720void TStreamerInfo::InsertArtificialElements(std::vector<const ROOT::TSchemaRule*> &rules)
4721{
4722 if (rules.empty()) return;
4723
4724 TIter next(fElements);
4725 UInt_t count = 0;
4726
4727 for(auto rule : rules) {
4728 if( rule->IsRenameRule() || rule->IsAliasRule() )
4729 continue;
4730 next.Reset();
4732 while ((element = (TStreamerElement*) next())) {
4733 if ( rule->HasTarget( element->GetName() ) ) {
4734
4735 // Check whether this is an 'attribute' rule.
4736 if ( rule->GetAttributes()[0] != 0 ) {
4737 TString attr( rule->GetAttributes() );
4738 attr.ToLower();
4739 if (attr.Contains("owner")) {
4740 if (attr.Contains("notowner")) {
4742 } else {
4744 }
4745 }
4746
4747 }
4748 break;
4749 }
4750 }
4751
4752 auto canIgnore = [](const ROOT::TSchemaRule *r) {
4753 if (r->GetAttributes()[0] != 0) {
4754 TString attr(r->GetAttributes());
4755 attr.ToLower();
4756 return attr.Contains("canignore");
4757 } else
4758 return false;
4759 };
4760 // NOTE: Before adding the rule we should check that the source do
4761 // existing in this StreamerInfo.
4762 const TObjArray *sources = rule->GetSource();
4763 if (sources)
4765 auto source_element = dynamic_cast<TStreamerElement *>(GetElements()->FindObject(src->GetName()));
4766 if (!source_element) {
4767 // It might still be in one the base classes.
4768 if (fClass->GetListOfRealData() && !fClass->GetListOfRealData()->FindObject(src->GetName())) {
4769 // Missing source.
4770 if (!canIgnore(rule)) {
4772 rule->AsString(ruleStr);
4773 Warning("InsertArtificialElements",
4774 "For class %s in StreamerInfo %d is missing the source data member `%s` when trying to "
4775 "apply the "
4776 "rule:\n %s",
4777 GetName(), GetClassVersion(), src->GetName(), ruleStr.Data());
4778 }
4779 rule = nullptr;
4780 break;
4781 }
4782 } else {
4783 // The source exists, let's check if it has the expected type.
4785 if ((memClass != source_element->GetNewClass() || memType != source_element->GetNewType()) &&
4787 const char *dim = src->GetDimensions();
4789 rule->AsString(ruleStr);
4790 auto cl = source_element->GetNewClass();
4792 if (memClass != cl) {
4793 classmsg = "and the memory TClass is \"";
4794 classmsg += cl ? cl->GetName() : "nullptr";
4795 classmsg += "\" while the rule needed \"";
4796 classmsg += memClass ? memClass->GetName() : "nullptr";
4797 classmsg += "\"";
4798 }
4799 Error("InsertArtificialElements",
4800 "For class %s in StreamerInfo %d a rule has conflicting type for the source \"%s %s%s\",\n"
4801 " The TStreamerElement has memory type %d (needed %d) %s:\n %s",
4802 GetName(), GetClassVersion(), src->GetTypeForDeclaration().Data(), src->GetName(),
4803 dim && dim[0] ? dim : "", source_element->GetNewType(), memType, classmsg.Data(),
4804 ruleStr.Data());
4805 rule = nullptr;
4806 break;
4807 }
4808 }
4809 }
4810
4811 if (!rule) continue;
4812
4814 std::vector<TStreamerArtificial*> toAdd;
4815
4816 if (rule->GetTarget()==0) {
4818 newName.Form("%s_rule%d",fClass->GetName(),count);
4822 "void");
4824 newel->SetReadFunc( rule->GetReadFunctionPointer() );
4825 newel->SetReadRawFunc( rule->GetReadRawFunctionPointer() );
4826 toAdd.push_back(newel);
4827 } else {
4828 toAdd.reserve(rule->GetTarget()->GetEntriesFast());
4829 TObjString * objstr = (TObjString*)(rule->GetTarget()->At(0));
4830 if (objstr) {
4831 TString newName = objstr->String();
4833 if ( TDataMember* dm = fClass->GetDataMember( newName ) ) {
4836 TStreamerInfo::kArtificial, dm->GetTypeName());
4837 newel->SetReadFunc( rule->GetReadFunctionPointer() );
4838 newel->SetReadRawFunc( rule->GetReadRawFunctionPointer() );
4839 toAdd.push_back(newel);
4840 } else {
4841 // This would be a completely new member (so it would need to be cached)
4842 // TOBEDONE
4843 }
4844 for(Int_t other = 1; other < rule->GetTarget()->GetEntriesFast(); ++other) {
4845 objstr = (TObjString*)(rule->GetTarget()->At(other));
4846 if (objstr) {
4847 newName = objstr->String();
4848 if ( TDataMember* dm = fClass->GetDataMember( newName ) ) {
4851 TStreamerInfo::kArtificial, dm->GetTypeName());
4852 toAdd.push_back(newel);
4853 }
4854 }
4855 }
4856 } // For each target of the rule
4857 }
4858 // Now find where with need to add them
4859 TIter s_iter(rule->GetSource());
4860 Int_t loc = -1;
4861 while( TObjString *s = (TObjString*)s_iter() ) {
4862 for(Int_t i = fElements->GetLast(); i >= 0 && (i+1) >= loc; --i) {
4863 if (s->String() == fElements->UncheckedAt(i)->GetName()) {
4864 if (loc == -1 || (i+1)>loc) {
4865 loc = i+1;
4866 }
4867 }
4868 }
4869 }
4870 if (loc == -1) {
4871 // Verify if the last one is not 'skipped'.
4872 for(Int_t i = fElements->GetLast(); i >= 0 && (i+1) >= loc; --i) {
4875 break;
4876 }
4877 loc = i;
4878 }
4879 }
4880 if (loc == -1) {
4881 for(auto &el : toAdd) {
4882 fElements->Add(el);
4883 }
4884 } else {
4886 }
4887 } // None of the target of the rule are on file.
4888}
4889
4890////////////////////////////////////////////////////////////////////////////////
4891/// List the TStreamerElement list and also the precomputed tables
4892/// if option contains the string "incOrig", also prints the original
4893/// (non-optimized elements in the list of compiled elements.
4894
4896{
4897 if (fClass && (fName != fClass->GetName())) {
4898 if (fClass->IsVersioned()) {
4899 Printf("\nStreamerInfo for conversion to %s from: %s, version=%d, checksum=0x%x",fClass->GetName(),GetName(),fClassVersion,GetCheckSum());
4900 } else {
4901 Printf("\nStreamerInfo for conversion to %s from: %s, checksum=0x%x",fClass->GetName(),GetName(),GetCheckSum());
4902 }
4903 } else {
4904 if (!fClass || fClass->IsVersioned()) {
4905 Printf("\nStreamerInfo for class: %s, version=%d, checksum=0x%x",GetName(),fClassVersion,GetCheckSum());
4906 } else {
4907 Printf("\nStreamerInfo for class: %s, checksum=0x%x",GetName(),GetCheckSum());
4908 }
4909 }
4910
4911 if (fElements) {
4912 TIter next(fElements);
4913 TObject *obj;
4914 while ((obj = next()))
4915 obj->ls(option);
4916 }
4917 if (strstr(option,"full") != 0) {
4918 for (Int_t i=0; i < fNfulldata; ++i) {
4921 element->GetSequenceType(sequenceType);
4922 // by definition of the loop (i+1) <= fNdata
4923 if (sequenceType.Length()) {
4924 sequenceType.Prepend(" [");
4925 sequenceType += "]";
4926 }
4927 Printf(" i=%2d, %-15s type=%3d, offset=%3d, len=%d, method=%ld%s",
4929 sequenceType.Data());
4930 }
4931
4932 } else {
4933 Bool_t wantOrig = strstr(option,"incOrig") != 0;
4935 for (Int_t i=0,j=0;i < fNdata;++i,++j) {
4938 element->GetSequenceType(sequenceType);
4939 // by definition of the loop (i+1) <= fNdata
4941 if (optimized) {
4942 // This was optimized.
4943 if (sequenceType.Length() != 0) {
4944 sequenceType += ',';
4945 }
4946 sequenceType += "optimized";
4947 }
4948 if (sequenceType.Length()) {
4949 sequenceType.Prepend(" [");
4950 sequenceType += "]";
4951 }
4952 Printf(" i=%2d, %-15s type=%3d, offset=%3d, len=%d, method=%ld%s",
4953 i,element->GetName(),fCompOpt[i]->fType,fCompOpt[i]->fOffset,fCompOpt[i]->fLength,fCompOpt[i]->fMethod,
4954 sequenceType.Data());
4955 if (optimized && wantOrig) {
4956 Bool_t done;
4957 do {
4958 element = (TStreamerElement*)fCompFull[j]->fElem;
4959 element->GetSequenceType(sequenceType);
4960 if (sequenceType.Length()) {
4961 sequenceType.Prepend(" [");
4962 sequenceType += "]";
4963 }
4964 Printf(" j=%2d, %-15s type=%3d, offset=%3d, len=%d, method=%ld%s",
4966 sequenceType.Data());
4967 ++j;
4968 done = j >= fNfulldata || ( (i+1 < fNdata) && fCompOpt[i+1]->fElem == fCompFull[j+1]->fElem );
4969 } while (!done);
4970
4971 }
4972 }
4973 }
4974}
4975
4976////////////////////////////////////////////////////////////////////////////////
4977/// An emulated object is created at address obj, if obj is null we
4978/// allocate memory for the object.
4979
4980void* TStreamerInfo::New(void *obj)
4981{
4982 //???FIX ME: What about varying length array elements?
4983
4984 char* p = (char*) obj;
4985
4986 TIter next(fElements);
4987
4988 if (!p) {
4989 // Allocate and initialize the memory block.
4990 p = new char[fSize];
4991 memset(p, 0, fSize);
4992 }
4993
4994 next.Reset();
4996
4997 for (; element; element = (TStreamerElement*) next()) {
4998
4999 // Skip elements which have not been allocated memory.
5000 if (element->GetOffset() == kMissing) {
5001 continue;
5002 }
5003
5004 // Skip elements for which we do not have any class
5005 // information. FIXME: Document how this could happen.
5006 TClass *cle = element->GetNewClass();
5007 if (!cle)
5008 cle = element->GetClassPointer();
5009 if (!cle)
5010 continue;
5011
5012 char* eaddr = p + element->GetOffset();
5013 Int_t etype = element->GetNewType();
5014 if (etype == TStreamerInfo::kNoType)
5015 etype = element->GetType();
5016
5017 //cle->GetStreamerInfo(); //necessary in case "->" is not specified
5018
5019 switch (etype) {
5020
5021 case kAnyP:
5022 case kObjectP:
5023 case kSTLp:
5024 {
5025 // Initialize array of pointers with null pointers.
5026 char** r = (char**) eaddr;
5027 Int_t len = element->GetArrayLength();
5028 for (Int_t i = 0; i < len; ++i) {
5029 r[i] = 0;
5030 }
5031 }
5032 break;
5033
5034 case kObjectp:
5035 case kAnyp:
5036 {
5037 // If the option "->" is given in the data member comment field
5038 // it is assumed that the object exists before reading data in,
5039 // so we create an object.
5040 if (cle != TClonesArray::Class()) {
5041 void** r = (void**) eaddr;
5042 *r = cle->New();
5043 } else {
5044 // In the case of a TClonesArray, the class name of
5045 // the contained objects must be specified in the
5046 // data member comment in this format:
5047 // TClonesArray* myVar; //->(className)
5048 const char* title = element->GetTitle();
5049 const char* bracket1 = strrchr(title, '(');
5050 const char* bracket2 = strrchr(title, ')');
5051 if (bracket1 && bracket2 && (bracket2 != (bracket1 + 1))) {
5052 Int_t len = bracket2 - (bracket1 + 1);
5053 char* clonesClass = new char[len+1];
5054 clonesClass[0] = '\0';
5056 void** r = (void**) eaddr;
5057 *r = (void*) new TClonesArray(clonesClass);
5058 delete[] clonesClass;
5059 } else {
5060 //Warning("New", "No class name found for TClonesArray initializer in data member comment (expected \"//->(className)\"");
5061 void** r = (void**) eaddr;
5062 *r = (void*) new TClonesArray();
5063 }
5064 }
5065 }
5066 break;
5067
5068 case kBase:
5069 {
5070 if (cle->Property() & kIsAbstract) {
5071 TVirtualStreamerInfo *einfo = cle->GetStreamerInfoAbstractEmulated();
5072 if (einfo) einfo->New(eaddr);
5073 } else {
5074 cle->New(eaddr);
5075 }
5076 break;
5077 }
5078 case kObject:
5079 case kAny:
5080 case kTObject:
5081 case kTString:
5082 case kTNamed:
5083 {
5084 cle->New(eaddr);
5085 }
5086 break;
5087
5088 case kSTL:
5089 {
5090 if (strcmp(element->GetName(),"This")==0 &&
5091 !cle->GetCollectionProxy()) {
5092 // missing information, avoid infinite loop
5093 // by doing nothing ....
5094 } else {
5095 if (cle->GetCollectionProxy())
5096 cle->GetCollectionProxy()->New(eaddr);
5097 else
5098 cle->New(eaddr);
5099 }
5100 }
5101 break;
5102
5103 case kObject + kOffsetL:
5104 case kAny + kOffsetL:
5105 case kTObject + kOffsetL:
5106 case kTString + kOffsetL:
5107 case kTNamed + kOffsetL:
5108 case kSTL + kOffsetL:
5109 {
5110 Int_t size = cle->Size();
5111 char* r = eaddr;
5112 Int_t len = element->GetArrayLength();
5113 for (Int_t i = 0; i < len; ++i, r += size) {
5114 cle->New(r);
5115 }
5116 }
5117 break;
5118
5119 } // switch etype
5120 } // for TIter next(fElements)
5121
5122 for(int nbase = 0; nbase < fNVirtualInfoLoc; ++nbase) {
5123 *(TStreamerInfo**)(p + fVirtualInfoLoc[nbase]) = this;
5124 }
5125 return p;
5126}
5127
5128////////////////////////////////////////////////////////////////////////////////
5129/// An array of emulated objects is created at address ary, if ary is null,
5130/// we allocate memory for the array.
5131
5133{
5134 if (fClass == 0) {
5135 Error("NewArray", "TClass pointer is null!");
5136 return 0;
5137 }
5138
5139 Int_t size = fClass->Size();
5140
5141 char* p = (char*) ary;
5142
5143 if (!p) {
5144 Long_t len = nElements * size + sizeof(Long_t)*2;
5145 p = new char[len];
5146 memset(p, 0, len);
5147 }
5148
5149 // Store the array cookie
5150 Long_t* r = (Long_t*) p;
5151 r[0] = size;
5152 r[1] = nElements;
5153 char* dataBegin = (char*) &r[2];
5154
5155 // Do a placement new for each element.
5156 p = dataBegin;
5157 for (Long_t cnt = 0; cnt < nElements; ++cnt) {
5158 New(p);
5159 p += size;
5160 } // for nElements
5161
5162 return dataBegin;
5163}
5164
5165
5166#define DeleteBasicPointer(addr,element,name) \
5167 { \
5168 name **f = (name**)(addr); \
5169 int n = element->GetArrayLength() ? element->GetArrayLength() : 1;\
5170 for(int j=0;j<n;j++) { \
5171 delete [] f[j]; \
5172 f[j] = 0; \
5173 } \
5174 }
5175
5176////////////////////////////////////////////////////////////////////////////////
5177/// Internal part of the destructor.
5178/// Destruct each of the datamembers in the same order
5179/// as the implicit destructor would.
5180
5182{
5183 R__ASSERT(obj != 0);
5184
5185 char *p = (char*)obj;
5186
5188 //for (; ele; ele = (TStreamerElement*) next())
5189 for (Int_t elenum = nelements - 1; elenum >= 0; --elenum) {
5191 if (ele->GetOffset() == kMissing) continue;
5192 char* eaddr = p + ele->GetOffset();
5193
5194 Int_t etype = ele->GetNewType(); // in memory type
5195 if (etype == TStreamerInfo::kNoType)
5196 etype = ele->GetType();
5197
5198 switch(etype) {
5215 }
5216
5217 TClass *cle = ele->GetNewClass(); // in memory type
5218 if (!cle)
5219 cle = ele->GetClassPointer();
5220 if (!cle)
5221 continue;
5222
5223 if (etype == kObjectp || etype == kAnyp) {
5224 // Destroy an array of pre-allocated objects.
5225 Int_t len = ele->GetArrayLength();
5226 if (!len) {
5227 len = 1;
5228 }
5229 void** r = (void**) eaddr;
5230 for (Int_t j = len - 1; j >= 0; --j) {
5231 if (r[j]) {
5232 cle->Destructor(r[j]);
5233 r[j] = 0;
5234 }
5235 }
5236 }
5237
5238 if ((etype == kObjectP || etype == kAnyP || etype == kSTLp) && !ele->TestBit(TStreamerElement::kDoNotDelete)) {
5239 // Destroy an array of pointers to not-pre-allocated objects.
5240 Int_t len = ele->GetArrayLength();
5241 if (!len) {
5242 len = 1;
5243 }
5244 void** r = (void**) eaddr;
5245 for (Int_t j = len - 1; j >= 0; --j) {
5246 if (r[j]) {
5247 cle->Destructor(r[j]);
5248 r[j] = 0;
5249 }
5250 }
5251 }
5252
5253 if (etype == kBase) {
5254 if (cle->Property() & kIsAbstract) {
5255 TVirtualStreamerInfo *einfo = cle->GetStreamerInfoAbstractEmulated();
5256 if (einfo) einfo->Destructor(eaddr, kTRUE);
5257 } else {
5258 cle->Destructor(eaddr, kTRUE);
5259 }
5260 }
5261
5262 if (etype == kObject || etype == kAny ||
5263 etype == kTObject || etype == kTString || etype == kTNamed) {
5264 // A data member is destroyed, but not deleted.
5265 cle->Destructor(eaddr, kTRUE);
5266 }
5267
5268 if (etype == kSTL) {
5269 // A data member is destroyed, but not deleted.
5270 TVirtualCollectionProxy *pr = cle->GetCollectionProxy();
5271 if (!pr) {
5272 if (strcmp(ele->GetName(),"This")==0) {
5273 // missing information, avoid infinite loop
5274 // by doing nothing ....
5275 } else {
5276 cle->Destructor(eaddr, kTRUE);
5277 }
5278 } else {
5279 if (ele->TestBit(TStreamerElement::kDoNotDelete)) {
5280 TVirtualCollectionProxy::TPushPop env(cle->GetCollectionProxy(), eaddr); // used for both this 'clear' and the 'clear' inside destructor.
5281 cle->GetCollectionProxy()->Clear(); // empty the collection without deleting the pointer
5282 pr->Destructor(eaddr, kTRUE);
5283 } else {
5284 pr->Destructor(eaddr, kTRUE);
5285 }
5286 }
5287 }
5288
5289 if (etype == kObject + kOffsetL || etype == kAny + kOffsetL ||
5290 etype == kTObject + kOffsetL || etype == kTString + kOffsetL ||
5291 etype == kTNamed + kOffsetL || etype == kSTL + kOffsetL) {
5292 // For a data member which is an array of objects, we
5293 // destroy the objects, but do not delete them.
5294 Int_t len = ele->GetArrayLength();
5295 Int_t size = cle->Size();
5296 char* r = eaddr + (size * (len - 1));
5297 for (Int_t j = len - 1; j >= 0; --j, r -= size) {
5298 cle->Destructor(r, kTRUE);
5299 }
5300 }
5301 } // iter over elements
5302
5303 if (!dtorOnly) {
5304 delete[] p;
5305 }
5306}
5307
5308////////////////////////////////////////////////////////////////////////////////
5309/// Emulated destructor for this class.
5310///
5311/// An emulated object is destroyed at address p.
5312/// Destruct each of the datamembers in the same order
5313/// as the implicit destructor would.
5314
5316{
5317 // Do nothing if passed a null pointer.
5318 if (obj == 0) return;
5319
5320 char* p = (char*) obj;
5321
5322 if (!dtorOnly && fNVirtualInfoLoc) {
5323 // !dtorOnly is used to filter out the case where this is called for
5324 // a base class or embedded object of the outer most class.
5325 TStreamerInfo *allocator = *(TStreamerInfo**)(p + fVirtualInfoLoc[0]);
5326 if (allocator != this) {
5327
5329
5330 p -= baseoffset;
5331 allocator->DestructorImpl(p, kFALSE);
5332 return;
5333 }
5334 }
5336}
5337
5338////////////////////////////////////////////////////////////////////////////////
5339/// Destroy an array of emulated objects, with optional delete.
5340
5342{
5343 // Do nothing if passed a null pointer.
5344 if (ary == 0) return;
5345
5346 //???FIX ME: What about varying length arrays?
5347
5348 Long_t* r = (Long_t*) ary;
5349 Long_t arrayLen = r[-1];
5350 Long_t size = r[-2];
5351 char* memBegin = (char*) &r[-2];
5352
5353 char* p = ((char*) ary) + ((arrayLen - 1) * size);
5354 for (Long_t cnt = 0; cnt < arrayLen; ++cnt, p -= size) {
5355 // Destroy each element, but do not delete it.
5356 Destructor(p, kTRUE);
5357 } // for arrayItemSize
5358
5359 if (!dtorOnly) {
5360 delete[] memBegin;
5361 }
5362}
5363
5364////////////////////////////////////////////////////////////////////////////////
5365/// print value of element i in object at pointer
5366/// The function may be called in two ways:
5367/// -method1 len < 0
5368/// i is assumed to be the TStreamerElement number i in StreamerInfo
5369/// -method2 len >= 0
5370/// i is the type
5371/// address of variable is directly pointer.
5372/// len is the number of elements to be printed starting at pointer.
5373
5374void TStreamerInfo::PrintValue(const char *name, char *pointer, Int_t i, Int_t len, Int_t lenmax) const
5375{
5376 char *ladd;
5378 printf(" %-15s = ",name);
5379
5381 Int_t *count = 0;
5382 if (len >= 0) {
5383 ladd = pointer;
5384 atype = i;
5385 aleng = len;
5386 } else {
5387 if (i < 0) {
5388 if (pointer==0) {
5389 printf("NULL\n");
5390 } else {
5391 const static TClassRef stringClass("string");
5392 if (fClass == stringClass) {
5393 std::string *st = (std::string*)(pointer);
5394 printf("%s\n",st->c_str());
5395 } else if (fClass == TString::Class()) {
5396 TString *st = (TString*)(pointer);
5397 printf("%s\n",st->Data());
5398 } else {
5399 printf("(%s*)0x%zx\n",GetName(),(size_t)pointer);
5400 }
5401 }
5402 return;
5403 }
5404 ladd = pointer + fCompFull[i]->fOffset;
5405 atype = fCompFull[i]->fNewType;
5406 aleng = fCompFull[i]->fLength;
5407 aElement = (TStreamerElement*)fCompFull[i]->fElem;
5408 count = (Int_t*)(pointer+fCompFull[i]->fMethod);
5409 }
5410 if (aleng > lenmax) aleng = lenmax;
5411
5413 printf("\n");
5414}
5415
5416////////////////////////////////////////////////////////////////////////////////
5417/// Print value of element i in a TClonesArray.
5418
5420{
5421 if (!clones) {printf(" %-15s = \n",name); return;}
5422 printf(" %-15s = ",name);
5423 Int_t nc = clones->GetEntriesFast();
5424 if (nc > lenmax) nc = lenmax;
5425
5428 int aleng = fCompFull[i]->fLength;
5429 if (aleng > lenmax) aleng = lenmax;
5430
5431 for (Int_t k=0;k < nc;k++) {
5432 char *pointer = (char*)clones->UncheckedAt(k);
5433 char *ladd = pointer+offset;
5434 Int_t *count = (Int_t*)(pointer+fCompFull[i]->fMethod);
5435 PrintValueAux(ladd,fCompFull[i]->fNewType,aElement, aleng, count);
5436 if (k < nc-1) printf(", ");
5437 }
5438 printf("\n");
5439}
5440
5441////////////////////////////////////////////////////////////////////////////////
5442/// Print value of element i in a TClonesArray.
5443
5445{
5446 if (!cont) {printf(" %-15s = \n",name); return;}
5447 printf(" %-15s = ",name);
5448 Int_t nc = cont->Size();
5449 if (nc > lenmax) nc = lenmax;
5450
5453 int aleng = fCompFull[i]->fLength;
5454 if (aleng > lenmax) aleng = lenmax;
5455
5456 for (Int_t k=0;k < nc;k++) {
5457 char *pointer = (char*)cont->At(k);
5458 char *ladd = pointer+offset;
5459 Int_t *count = (Int_t*)(pointer+fCompFull[i]->fMethod);
5460 PrintValueAux(ladd,fCompFull[i]->fNewType,aElement, aleng, count);
5461 if (k < nc-1) printf(", ");
5462 }
5463 printf("\n");
5464}
5465
5466////////////////////////////////////////////////////////////////////////////////
5467/// Replace the TClass this streamerInfo is pointing to (belongs to)
5468
5470{
5471 if (newcl) {
5472 // This is mostly (but not only) for the artificial "This" streamerElement for an stl collection.
5474 }
5475 fClass = newcl;
5476}
5477
5478////////////////////////////////////////////////////////////////////////////////
5479/// Stream an object of class TStreamerInfo.
5480
5482{
5483 UInt_t R__s, R__c;
5484 if (R__b.IsReading()) {
5485 Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
5486 fOldVersion = R__v;
5487 if (R__v > 1) {
5488 //R__b.ReadClassBuffer(TStreamerInfo::Class(), this, R__v, R__s, R__c);
5489 R__b.ClassBegin(TStreamerInfo::Class(), R__v);
5490 R__b.ClassMember("TNamed");
5493 R__b.ClassMember("fCheckSum","UInt_t");
5494 R__b >> fCheckSum;
5495 R__b.ClassMember("fClassVersion","Int_t");
5498 R__b.ClassMember("fElements","TObjArray*");
5499 R__b >> fElements;
5500 R__b.ClassEnd(TStreamerInfo::Class());
5501 R__b.SetBufferOffset(R__s+R__c+sizeof(UInt_t));
5505
5506 if (R__b.GetParent() && R__b.GetVersionOwner() < 50000)
5507 {
5508 // In some older files, the type of the TStreamerElement was not
5509 // as we (now) expect.
5512 for (Int_t i = 0; i < nobjects; i++) {
5514 TStreamerElement *rel = 0;
5515 if ( el->IsA() == basic ) {
5516 switch (el->GetType()) {
5517 default: break; /* nothing */
5518 case TStreamerInfo::kObject: /*61*/
5519 rel = new TStreamerObject(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5520 break;
5521 case TStreamerInfo::kAny: /*62*/
5522 rel = new TStreamerObjectAny(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5523 break;
5524 case TStreamerInfo::kObjectp: /* 63 */
5525 rel = new TStreamerObjectPointer(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5526 break;
5527 case TStreamerInfo::kObjectP: /* 64 */
5528 rel = new TStreamerObjectPointer(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5529 break;
5530 case TStreamerInfo::kTString: /* 65 */
5531 rel = new TStreamerObject(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5532 break;
5533 }
5534 if (rel) {
5535 (*fElements)[i] = rel;
5536 delete el;
5537 }
5538 }
5539 }
5540 }
5541 return;
5542 }
5543 //====process old versions before automatic schema evolution
5546 R__b >> fCheckSum;
5549 R__b >> fElements;
5550 R__b.CheckByteCount(R__s, R__c, TStreamerInfo::IsA());
5551 } else {
5552 R__c = R__b.WriteVersion(TStreamerInfo::IsA(), kTRUE);
5553 R__b.ClassBegin(TStreamerInfo::Class());
5554 R__b.ClassMember("TNamed");
5556 R__b.ClassMember("fCheckSum","UInt_t");
5557 R__b << fCheckSum;
5558 R__b.ClassMember("fClassVersion","Int_t");
5560
5561 //------------------------------------------------------------------------
5562 // Stream only non-artificial streamer elements
5563 //////////////////////////////////////////////////////////////////////////
5564
5565 R__b.ClassMember("fElements","TObjArray*");
5566 {
5567 TObjArray elements(fElements->GetEntriesFast());
5570 for (Int_t i = 0; i < nobjects; i++) {
5572 if (el != 0 && (el->IsA() == TStreamerArtificial::Class() || el->TestBit(TStreamerElement::kRepeat))) {
5573 // skip
5574 } else if (el != 0 && (el->TestBit(TStreamerElement::kCache) && !el->TestBit(TStreamerElement::kWrite))) {
5575 // skip
5576 } else if (el != 0) {
5577 elements.AddLast(el);
5578 }
5579 }
5580 R__b.WriteObjectAny(&elements, TObjArray::Class(), kFALSE);
5581 }
5582 R__b.ClassEnd(TStreamerInfo::Class());
5583 R__b.SetByteCount(R__c, kTRUE);
5584 }
5585}
5586
5587////////////////////////////////////////////////////////////////////////////////
5588/// Mark the classindex of the current file as using this TStreamerInfo.
5589/// This function is deprecated and its functionality is now done by
5590/// the overloads of TBuffer::TagStreamerInfo.
5591
5593{
5594 if (file) {
5595 // If the value of the atomic is kFALSE (equal to expected), change its value
5596 // to kTRUE and return true. Leave it as it is otherwise and return false.
5597 static std::atomic<Bool_t> onlyonce(kFALSE);
5599 if (onlyonce.compare_exchange_strong(expected,kTRUE)) {
5600 Warning("TagFile","This function is deprecated, use TBuffer::TagStreamerInfo instead");
5601 }
5602 TArrayC *cindex = file->GetClassIndex();
5603 Int_t nindex = cindex->GetSize();
5605 Error("TagFile","StreamerInfo: %s number: %d out of range[0,%d] in file: %s",
5606 GetName(),fNumber,nindex,file->GetName());
5607 return;
5608 }
5609 if (cindex->fArray[fNumber] == 0) {
5610 cindex->fArray[0] = 1;
5611 cindex->fArray[fNumber] = 1;
5612 }
5613 }
5614}
5615
5616////////////////////////////////////////////////////////////////////////////////
5617
5618#ifdef DOLOOP
5619#undef DOLOOP
5620#endif
5621#define DOLOOP for (k = 0, pointer = arr[0]; k < narr; pointer = arr[++k])
5622
5623namespace {
5624 static void PrintCR(int j,Int_t aleng, UInt_t ltype)
5625 {
5626 if (j == aleng-1) printf("\n");
5627 else {
5628 printf(", ");
5629 if (j%ltype == ltype-1) printf("\n ");
5630 }
5631 }
5632}
5633
5634////////////////////////////////////////////////////////////////////////////////
5635/// print value of element in object at pointer, type atype, leng aleng or *count
5636/// The function may be called in two ways:
5637/// -method1 len < 0
5638/// i is assumed to be the TStreamerElement number i in StreamerInfo
5639/// -method2 len >= 0
5640/// i is the type
5641/// address of variable is directly pointer.
5642/// len is the number of elements to be printed starting at pointer.
5643
5645{
5646 int j;
5647
5648 //assert(!((kOffsetP + kChar) <= atype && atype <= (kOffsetP + kBool) && count == 0));
5649 switch (atype) {
5650 // basic types
5651 case kBool: {Bool_t *val = (Bool_t* )ladd; printf("%d" ,*val); break;}
5652 case kChar: {Char_t *val = (Char_t* )ladd; printf("%d" ,*val); break;}
5653 case kShort: {Short_t *val = (Short_t* )ladd; printf("%d" ,*val); break;}
5654 case kInt: {Int_t *val = (Int_t* )ladd; printf("%d" ,*val); break;}
5655 case kLong: {Long_t *val = (Long_t* )ladd; printf("%ld",*val); break;}
5656 case kLong64: {Long64_t *val = (Long64_t* )ladd; printf("%lld",*val); break;}
5657 case kFloat: {Float_t *val = (Float_t* )ladd; printf("%f" ,*val); break;}
5658 case kFloat16: {Float_t *val = (Float_t* )ladd; printf("%f" ,*val); break;}
5659 case kDouble: {Double_t *val = (Double_t* )ladd; printf("%g" ,*val); break;}
5660 case kDouble32: {Double_t *val = (Double_t* )ladd; printf("%g" ,*val); break;}
5661 case kUChar: {UChar_t *val = (UChar_t* )ladd; printf("%u" ,*val); break;}
5662 case kUShort: {UShort_t *val = (UShort_t* )ladd; printf("%u" ,*val); break;}
5663 case kUInt: {UInt_t *val = (UInt_t* )ladd; printf("%u" ,*val); break;}
5664 case kULong: {ULong_t *val = (ULong_t* )ladd; printf("%lu",*val); break;}
5665 case kULong64: {ULong64_t *val = (ULong64_t*)ladd; printf("%llu",*val); break;}
5666 case kBits: {UInt_t *val = (UInt_t* )ladd; printf("%d" ,*val); break;}
5667
5668 // array of basic types array[8]
5669 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;}
5670 case kOffsetL + kChar: {Char_t *val = (Char_t* )ladd; for(j=0;j<aleng;j++) { printf("%c " ,val[j]); PrintCR(j,aleng,20); } break;}
5671 case kOffsetL + kShort: {Short_t *val = (Short_t* )ladd; for(j=0;j<aleng;j++) { printf("%d " ,val[j]); PrintCR(j,aleng,10); } break;}
5672 case kOffsetL + kInt: {Int_t *val = (Int_t* )ladd; for(j=0;j<aleng;j++) { printf("%d " ,val[j]); PrintCR(j,aleng,10); } break;}
5673 case kOffsetL + kLong: {Long_t *val = (Long_t* )ladd; for(j=0;j<aleng;j++) { printf("%ld ",val[j]); PrintCR(j,aleng, 5); } break;}
5674 case kOffsetL + kLong64: {Long64_t *val = (Long64_t* )ladd; for(j=0;j<aleng;j++) { printf("%lld ",val[j]);PrintCR(j,aleng, 5); } break;}
5675 case kOffsetL + kFloat: {Float_t *val = (Float_t* )ladd; for(j=0;j<aleng;j++) { printf("%f " ,val[j]); PrintCR(j,aleng, 5); } break;}
5676 case kOffsetL + kFloat16: {Float_t *val = (Float_t* )ladd; for(j=0;j<aleng;j++) { printf("%f " ,val[j]); PrintCR(j,aleng, 5); } break;}
5677 case kOffsetL + kDouble: {Double_t *val = (Double_t* )ladd; for(j=0;j<aleng;j++) { printf("%g " ,val[j]); PrintCR(j,aleng, 5); } break;}
5678 case kOffsetL + kDouble32:{Double_t *val = (Double_t* )ladd; for(j=0;j<aleng;j++) { printf("%g " ,val[j]); PrintCR(j,aleng, 5); } break;}
5679 case kOffsetL + kUChar: {UChar_t *val = (UChar_t* )ladd; for(j=0;j<aleng;j++) { printf("%u " ,val[j]); PrintCR(j,aleng,20); } break;}
5680 case kOffsetL + kUShort: {UShort_t *val = (UShort_t* )ladd; for(j=0;j<aleng;j++) { printf("%u " ,val[j]); PrintCR(j,aleng,10); } break;}
5681 case kOffsetL + kUInt: {UInt_t *val = (UInt_t* )ladd; for(j=0;j<aleng;j++) { printf("%u " ,val[j]); PrintCR(j,aleng, 5); } break;}
5682 case kOffsetL + kULong: {ULong_t *val = (ULong_t* )ladd; for(j=0;j<aleng;j++) { printf("%lu ",val[j]); PrintCR(j,aleng, 5); } break;}
5683 case kOffsetL + kULong64: {ULong64_t *val = (ULong64_t*)ladd; for(j=0;j<aleng;j++) { printf("%llu ",val[j]);PrintCR(j,aleng, 5); } break;}
5684 case kOffsetL + kBits: {UInt_t *val = (UInt_t* )ladd; for(j=0;j<aleng;j++) { printf("%d " ,val[j]); PrintCR(j,aleng, 5); } break;}
5685
5686 // pointer to an array of basic types array[n]
5687 case kOffsetP + kBool: {Bool_t **val = (Bool_t** )ladd; for(j=0;j<*count;j++) { printf("%d " ,(*val)[j]); PrintCR(j,aleng,20); } break;}
5688 case kOffsetP + kChar: {Char_t **val = (Char_t** )ladd; for(j=0;j<*count;j++) { printf("%d " ,(*val)[j]); PrintCR(j,aleng,20); } break;}
5689 case kOffsetP + kShort: {Short_t **val = (Short_t** )ladd; for(j=0;j<*count;j++) { printf("%d " ,(*val)[j]); PrintCR(j,aleng,10); } break;}
5690 case kOffsetP + kInt: {Int_t **val = (Int_t** )ladd; for(j=0;j<*count;j++) { printf("%d " ,(*val)[j]); PrintCR(j,aleng,10); } break;}
5691 case kOffsetP + kLong: {Long_t **val = (Long_t** )ladd; for(j=0;j<*count;j++) { printf("%ld ",(*val)[j]); PrintCR(j,aleng, 5); } break;}
5692 case kOffsetP + kLong64: {Long64_t **val = (Long64_t**)ladd; for(j=0;j<*count;j++) { printf("%lld ",(*val)[j]); PrintCR(j,aleng, 5); } break;}
5693 case kOffsetP + kFloat: {Float_t **val = (Float_t** )ladd; for(j=0;j<*count;j++) { printf("%f " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5694 case kOffsetP + kFloat16: {Float_t **val = (Float_t** )ladd; for(j=0;j<*count;j++) { printf("%f " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5695 case kOffsetP + kDouble: {Double_t **val = (Double_t**)ladd; for(j=0;j<*count;j++) { printf("%g " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5696 case kOffsetP + kDouble32:{Double_t **val = (Double_t**)ladd; for(j=0;j<*count;j++) { printf("%g " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5697 case kOffsetP + kUChar: {UChar_t **val = (UChar_t** )ladd; for(j=0;j<*count;j++) { printf("%u " ,(*val)[j]); PrintCR(j,aleng,20); } break;}
5698 case kOffsetP + kUShort: {UShort_t **val = (UShort_t**)ladd; for(j=0;j<*count;j++) { printf("%u " ,(*val)[j]); PrintCR(j,aleng,10); } break;}
5699 case kOffsetP + kUInt: {UInt_t **val = (UInt_t** )ladd; for(j=0;j<*count;j++) { printf("%u " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5700 case kOffsetP + kULong: {ULong_t **val = (ULong_t** )ladd; for(j=0;j<*count;j++) { printf("%lu ",(*val)[j]); PrintCR(j,aleng, 5); } break;}
5701 case kOffsetP + kULong64: {ULong64_t**val = (ULong64_t**)ladd; for(j=0;j<*count;j++){ printf("%llu ",(*val)[j]); PrintCR(j,aleng, 5); } break;}
5702
5703 // array counter //[n]
5704 case kCounter: {Int_t *val = (Int_t*)ladd; printf("%d",*val); break;}
5705 // char *
5706 case kCharStar:{
5707 char **val = (char**)ladd;
5708 if (*val) printf("%s",*val);
5709 break;
5710 }
5711 // Class * derived from TObject with comment field //->
5712 case kObjectp: {
5713 TObject **obj = (TObject**)(ladd);
5715 printf("(%s*)%zx",el ? el->GetClass()->GetName() : "unknown_type",(size_t)(*obj));
5716 break;
5717 }
5718
5719 // Class* derived from TObject
5720 case kObjectP: {
5721 TObject **obj = (TObject**)(ladd);
5723 printf("(%s*)%zx",el ? el->GetClass()->GetName() : "unknown_type",(size_t)(*obj));
5724 break;
5725 }
5726
5727 // Class derived from TObject
5728 case kObject: {
5729 TObject *obj = (TObject*)(ladd);
5730 printf("%s",obj->GetName());
5731 break;
5732 }
5733
5734 // Special case for TString, TObject, TNamed
5735 case kTString: {
5736 TString *st = (TString*)(ladd);
5737 printf("%s",st->Data());
5738 break;
5739 }
5740 case kTObject: {
5741 TObject *obj = (TObject*)(ladd);
5742 printf("%s",obj->GetName());
5743 break;
5744 }
5745 case kTNamed: {
5746 TNamed *named = (TNamed*) (ladd);
5747 printf("%s/%s",named->GetName(),named->GetTitle());
5748 break;
5749 }
5750
5751 // Class * not derived from TObject with comment field //->
5752 case kAnyp: {
5753 TObject **obj = (TObject**)(ladd);
5755 printf("(%s*)0x%zx",el ? el->GetClass()->GetName() : "unknown_type",(size_t)(*obj));
5756 break;
5757 }
5758
5759 // Class* not derived from TObject
5760 case kAnyP: {
5761 TObject **obj = (TObject**)(ladd);
5763 printf("(%s*)0x%zx",el ? el->GetClass()->GetName() : "unknown_type",(size_t)(*obj));
5764 break;
5765 }
5766 // Any Class not derived from TObject
5767 case kOffsetL + kObjectp:
5768 case kOffsetL + kObjectP:
5769 case kAny: {
5770 printf("printing kAny case (%d)",atype);
5771// if (aElement) {
5772// TMemberStreamer *pstreamer = aElement->GetStreamer();
5773// if (pstreamer == 0) {
5774// //printf("ERROR, Streamer is null\n");
5775// //aElement->ls();
5776// break;
5777// }
5778// //(*pstreamer)(b,ladd,0);
5779// }
5780 break;
5781 }
5782 // Base Class
5783 case kBase: {
5784 printf("printing kBase case (%d)",atype);
5785 //aElement->ReadBuffer(b,pointer);
5786 break;
5787 }
5788
5789 case kOffsetL + kObject:
5790 case kOffsetL + kTString:
5791 case kOffsetL + kTObject:
5792 case kOffsetL + kTNamed:
5793 case kStreamer: {
5794 printf("printing kStreamer case (%d)",atype);
5795// TMemberStreamer *pstreamer = aElement->GetStreamer();
5796// if (pstreamer == 0) {
5797// //printf("ERROR, Streamer is null\n");
5798// //aElement->ls();
5799// break;
5800// }
5801// //UInt_t start,count;
5802// //b.ReadVersion(&start, &count);
5803// //(*pstreamer)(b,ladd,0);
5804// //b.CheckByteCount(start,count,IsA());
5805 break;
5806 }
5807
5808 case kStreamLoop: {
5809 printf("printing kStreamLoop case (%d)",atype);
5810// TMemberStreamer *pstreamer = aElement->GetStreamer();
5811// if (pstreamer == 0) {
5812// //printf("ERROR, Streamer is null\n");
5813// //aElement->ls();
5814// break;
5815// }
5816 //Int_t *counter = (Int_t*)(count);
5817 //UInt_t start,count;
5818 ///b.ReadVersion(&start, &count);
5819 //(*pstreamer)(b,ladd,*counter);
5820 //b.CheckByteCount(start,count,IsA());
5821 break;
5822 }
5823 case kSTL: {
5824 if (aElement) {
5825 static TClassRef stringClass("string");
5826 if (ladd && aElement->GetClass() == stringClass) {
5827 std::string *st = (std::string*)(ladd);
5828 printf("%s",st->c_str());
5829 } else {
5830 printf("(%s*)0x%zx",aElement->GetClass()->GetName(),(size_t)(ladd));
5831 }
5832 } else {
5833 printf("(unknown_type*)0x%zx",(size_t)(ladd));
5834 }
5835 break;
5836 }
5837 }
5838}
5839
5840////////////////////////////////////////////////////////////////////////////////
5841///function called by the TClass constructor when replacing an emulated class
5842///by the real class
5843
5845{
5848 while ((element = (TStreamerElement*)nextElement())) {
5849 element->Update(oldcl,newcl);
5850 }
5851 for (Int_t i=0;i < fNslots;i++) {
5852 fComp[i].Update(oldcl,newcl);
5853 }
5854}
5855
5856////////////////////////////////////////////////////////////////////////////////
5857/// Update the TClass pointer cached in this object.
5858
5860{
5861 if (fType != -1) {
5862 if (fClass == oldcl || strcmp(fClassName, newcl->GetName()) == 0)
5863 fClass = newcl;
5864 else if (fClass == 0 && TClassTable::GetDict(fClassName))
5866 }
5867}
5868
5869////////////////////////////////////////////////////////////////////////////////
5870/// Generate emulated collection proxy for a given class.
5871
5877
5878////////////////////////////////////////////////////////////////////////////////
5879/// Generate emulated class streamer for a given collection class.
5880
5886
5887////////////////////////////////////////////////////////////////////////////////
5888/// Generate proxy from static functions.
5889
5891TStreamerInfo::GenExplicitProxy( const ::ROOT::TCollectionProxyInfo &info, TClass *cl )
5892{
5894}
5895
5896////////////////////////////////////////////////////////////////////////////////
5897/// Generate class streamer from static functions.
5898
5900TStreamerInfo::GenExplicitClassStreamer( const ::ROOT::TCollectionProxyInfo &info, TClass *cl )
5901{
5903}
5904
5905//
5906// Utility functions
5907//
5908static TStreamerElement* R__CreateEmulatedElement(const char *dmName, const std::string &dmFull, Int_t offset, bool silent)
5909{
5910 // Create a TStreamerElement for the type 'dmFull' and whose data member name is 'dmName'.
5911
5912 TString s1( TClassEdit::ShortType(dmFull.c_str(),0) );
5914 Bool_t dmIsPtr = (s1 != dmType);
5915 const char *dmTitle = "Emulation";
5916
5917 TDataType *dt = gROOT->GetType(dmType);
5918 if (dt && dt->GetType() > 0 ) { // found a basic type
5920 dtype = dt->GetType();
5921 dsize = dt->Size();
5922 if (dmIsPtr && dtype != kCharStar) {
5923 if (!silent)
5924 Error("Pair Emulation Building","%s is not yet supported in pair emulation",
5925 dmFull.c_str());
5926 return 0;
5927 } else {
5929 el->SetSize(dsize);
5930 return el;
5931 }
5932 } else {
5933
5934 static const char *full_string_name = "basic_string<char,char_traits<char>,allocator<char> >";
5935 if (strcmp(dmType,"string") == 0 || strcmp(dmType,"std::string") == 0 || strcmp(dmType,full_string_name)==0 ) {
5937 }
5939 return new TStreamerSTL(dmName,dmTitle,offset,dmFull.c_str(),dmFull.c_str(),dmIsPtr);
5940 }
5942 if (!clm) {
5944 if (enumdesc) {
5945 auto dtype = enumdesc->GetUnderlyingType();
5946 auto el = new TStreamerBasicType(dmName, dmTitle, offset, dtype, dmFull.c_str());
5948 if (datatype)
5949 el->SetSize(datatype->Size());
5950 else
5951 el->SetSize(sizeof(int)); // Default size of enums.
5952 return el;
5953 }
5954 return nullptr;
5955 }
5956 if (clm->GetState() <= TClass::kForwardDeclared)
5957 return nullptr;
5958 // a pointer to a class
5959 if ( dmIsPtr ) {
5960 if (clm->IsTObject()) {
5962 } else {
5964 }
5965 }
5966 // a class
5967 if (clm->IsTObject()) {
5968 return new TStreamerObject(dmName,dmTitle,offset,dmFull.c_str());
5969 } else if(clm == TString::Class() && !dmIsPtr) {
5971 } else {
5972 return new TStreamerObjectAny(dmName,dmTitle,offset,dmFull.c_str());
5973 }
5974 }
5975}
5976
5977/// \brief Generate the TClass and TStreamerInfo for the requested pair.
5978/// This creates a TVirtualStreamerInfo for the pair and trigger the BuildCheck/Old to
5979/// provoke the creation of the corresponding TClass. This relies on the dictionary for
5980/// std::pair<const int, int> to already exist (or the interpreter information being available)
5981/// as it is used as a template.
5982/// \note The returned object is owned by the caller.
5984{
5985 // Generate a TStreamerInfo for a std::pair<fname,sname>
5986 // This TStreamerInfo is then used as if it was read from a file to generate
5987 // and emulated TClass.
5988
5990 const char *msg = "problematic";
5992 msg = "the same";
5993 else if (hint_pair_offset > hint_pair_size) {
5994 if (hint_pair_size == 0)
5995 msg = "not specified";
5996 else
5997 msg = "smaller";
5998 }
5999 Error("GenerateInfoForPair",
6000 "Called with inconsistent offset and size. For \"std::pair<%s,%s>\" the requested offset is %ld but the size is %s (%ld)",
6001 firstname.c_str(), secondname.c_str(), (long)hint_pair_offset, msg, (long)hint_pair_offset);
6002 return nullptr;
6003 }
6004 TStreamerInfo *i = (TStreamerInfo*)TClass::GetClass("pair<const int,int>")->GetStreamerInfo()->Clone();
6005 std::string pname = "pair<" + firstname + "," + secondname;
6006 pname += (pname[pname.length()-1]=='>') ? " >" : ">";
6007 i->SetName(pname.c_str());
6008 i->SetClass(nullptr);
6009 i->GetElements()->Delete();
6011 Int_t size = 0;
6012 if (fel) {
6013 i->GetElements()->Add( fel );
6014
6015 size = fel->GetSize();
6016 Int_t sp = sizeof(void *);
6017 //align the non-basic data types (required on alpha and IRIX!!)
6018 if (size%sp != 0) size = size - size%sp + sp;
6019 } else {
6020 delete i;
6021 return 0;
6022 }
6023 if (hint_pair_offset)
6026 if (second) {
6027 i->GetElements()->Add( second );
6028 } else {
6029 delete i;
6030 return 0;
6031 }
6033 // Hide the warning about the missing pair dictionary.
6035 i->BuildCheck(nullptr, kFALSE); // Skipping the loading part (it would leads to infinite recursion on this very routine)
6037 // In the state emulated, BuildOld would recalculate the offset and undo the offset update.
6038 // Note: we should consider adding a new state just for this (the hints indicates that we are mapping a compiled class but
6039 // then we would have to investigate all use of the state with <= and >= condition to make sure they are still appropriate).
6040 if (hint_pair_size) {
6043 }
6044
6045 i->BuildOld();
6046
6047 if (hint_pair_size)
6049 return i;
6050}
6051
6053{
6054 const static int pairlen = std::char_traits<char>::length("pair<");
6055 if (pairclassname.compare(0, pairlen, "pair<") != 0) {
6056 if (!silent)
6057 Error("GenerateInfoForPair", "The class name passed is not a pair: %s", pairclassname.c_str());
6058 return nullptr;
6059 }
6060
6061 std::vector<std::string> inside;
6062 int nested = 0;
6063 int num = TClassEdit::GetSplit(pairclassname.c_str(), inside, nested);
6064 if (num != 4) {
6065 if (!silent)
6066 Error("GenerateInfoForPair", "Could not find the pair arguments in %s", pairclassname.c_str());
6067 return nullptr;
6068 }
6069
6070 return GenerateInfoForPair(inside[1], inside[2], silent, hint_pair_offset, hint_pair_size);
6071}
#define d(i)
Definition RSha256.hxx:102
#define f(i)
Definition RSha256.hxx:104
#define c(i)
Definition RSha256.hxx:101
#define s1(x)
Definition RSha256.hxx:91
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
bool Bool_t
Definition RtypesCore.h:63
int Int_t
Definition RtypesCore.h:45
short Version_t
Definition RtypesCore.h:65
char Char_t
Definition RtypesCore.h:37
unsigned long ULong_t
Definition RtypesCore.h:55
long Long_t
Definition RtypesCore.h:54
unsigned int UInt_t
Definition RtypesCore.h:46
float Float_t
Definition RtypesCore.h:57
short Short_t
Definition RtypesCore.h:39
constexpr Bool_t kFALSE
Definition RtypesCore.h:94
double Double_t
Definition RtypesCore.h:59
long double LongDouble_t
Definition RtypesCore.h:61
long long Long64_t
Definition RtypesCore.h:69
constexpr Bool_t kTRUE
Definition RtypesCore.h:93
const char Option_t
Definition RtypesCore.h:66
#define ClassImp(name)
Definition Rtypes.h:374
const Bool_t kIterBackward
Definition TCollection.h:43
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
EDataType
Definition TDataType.h:28
@ kNoType_t
Definition TDataType.h:33
@ kFloat_t
Definition TDataType.h:31
@ kULong64_t
Definition TDataType.h:32
@ kInt_t
Definition TDataType.h:30
@ kLong_t
Definition TDataType.h:30
@ kDouble32_t
Definition TDataType.h:31
@ kShort_t
Definition TDataType.h:29
@ kBool_t
Definition TDataType.h:32
@ kULong_t
Definition TDataType.h:30
@ kLong64_t
Definition TDataType.h:32
@ kUShort_t
Definition TDataType.h:29
@ kDouble_t
Definition TDataType.h:31
@ kCharStar
Definition TDataType.h:34
@ kChar_t
Definition TDataType.h:29
@ kUChar_t
Definition TDataType.h:29
@ kUInt_t
Definition TDataType.h:30
@ kFloat16_t
Definition TDataType.h:33
@ kOther_t
Definition TDataType.h:32
Bool_t operator!=(const TDatime &d1, const TDatime &d2)
Definition TDatime.h:104
@ kIsUnionMember
Definition TDictionary.h:74
@ kIsAbstract
Definition TDictionary.h:71
@ kIsStatic
Definition TDictionary.h:80
const Int_t kMaxLen
#define gDirectory
Definition TDirectory.h:384
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
constexpr Int_t kError
Definition TError.h:47
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition TError.cxx:185
Int_t gErrorIgnoreLevel
Error handling routines.
Definition TError.cxx:31
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t option
Option_t Option_t cindex
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char filename
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h offset
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize id
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t UChar_t len
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t attr
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t src
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
char name[80]
Definition TGX11.cxx:110
R__EXTERN TVirtualMutex * gInterpreterMutex
Int_t gDebug
Definition TROOT.cxx:597
#define gROOT
Definition TROOT.h:406
static void R__WriteMoveConstructorBody(FILE *file, const TString &protoname, TIter &next)
Write down the body of the 'move' constructor.
EUniquePtrOffset
static TStreamerElement * R__CreateEmulatedElement(const char *dmName, const std::string &dmFull, Int_t offset, bool silent)
static void R__TObjArray_InsertAt(TObjArray *arr, TObject *obj, Int_t at)
static void R__TObjArray_InsertAfter(TObjArray *arr, TObject *newobj, TObject *oldobj)
static bool R__IsUniquePtr(TStreamerElement *element)
Return true if the element is auto_ptr or unique_ptr.
#define READ_ARRAY(TYPE_t)
const Int_t kMaxLen
static void R__WriteConstructorBody(FILE *file, TIter &next)
#define DeleteBasicPointer(addr, element, name)
static constexpr int str_length(const char *str)
static void R__WriteMoveBodyPointersArrays(FILE *file, const TString &protoname, TIter &next)
Write down the pointers and arrays part of the body of the 'move' constructor.
static void R__TObjArray_InsertBefore(TObjArray *arr, TObject *newobj, TObject *oldobj)
static void R__WriteOddOperatorEqualBody(FILE *file, const TString &protoname, TIter &next)
Write down the body of the 'move' constructor.
static void R__WriteDestructorBody(FILE *file, TIter &next)
void Printf(const char *fmt,...)
Formats a string in a circular formatting buffer and prints the string.
Definition TString.cxx:2503
R__EXTERN TSystem * gSystem
Definition TSystem.h:572
#define R__LOCKGUARD(mutex)
#define snprintf
Definition civetweb.c:1540
Int_t GetPointerLevel() const
Definition TSchemaRule.h:48
const char * GetUnderlyingTypeName() const
Definition TSchemaRule.h:50
const char * GetDimensions() const
Definition TSchemaRule.h:44
Array of chars or bytes (8 bits per element).
Definition TArrayC.h:27
Each class (see TClass) has a linked list of its base class(es).
Definition TBaseClass.h:33
Int_t GetDelta()
Get offset from "this" to part of base class.
ROOT::ESTLType IsSTLContainer()
Return which type (if any) of STL container the data member is.
TClass * GetClassPointer(Bool_t load=kTRUE)
Get pointer to the base class TClass.
const char * GetTitle() const override
Get base class description (comment).
Buffer base class used for serializing objects.
Definition TBuffer.h:43
TClassRef is used to implement a permanent reference to a TClass object.
Definition TClassRef.h: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:6614
Bool_t IsSyntheticPair() const
Definition TClass.h:528
TDataMember * GetDataMember(const char *datamember) const
Return pointer to datamember object with name "datamember".
Definition TClass.cxx:3540
EState GetState() const
Definition TClass.h:495
ROOT::ESTLType GetCollectionType() const
Return the 'type' of the STL the TClass is representing.
Definition TClass.cxx:2987
void RemoveStreamerInfo(Int_t slot)
Remove and delete the StreamerInfo in the given slot.
Definition TClass.cxx:7470
Bool_t HasDataMemberInfo() const
Definition TClass.h:413
void CopyCollectionProxy(const TVirtualCollectionProxy &)
Replaces the collection proxy for this class.
Definition TClass.cxx:2571
Bool_t fIsSyntheticPair
Indicates whether this class can be split or not. Values are -1, 0, 1, 2.
Definition TClass.h:253
void RegisterStreamerInfo(TVirtualStreamerInfo *info)
Register the StreamerInfo in the given slot, change the State of the TClass as appropriate.
Definition TClass.cxx:7446
TVirtualStreamerInfo * GetCurrentStreamerInfo()
Definition TClass.h:446
void IgnoreTObjectStreamer(Bool_t ignore=kTRUE)
When the class kIgnoreTObjectStreamer bit is set, the automatically generated Streamer will not call ...
Definition TClass.cxx:4938
TClass * GetBaseClass(const char *classname)
Return pointer to the base class "classname".
Definition TClass.cxx:2756
Longptr_t GetDataMemberOffset(const char *membername) const
return offset for member name.
Definition TClass.cxx:3578
Bool_t MatchLegacyCheckSum(UInt_t checksum) const
Return true if the checksum passed as argument is one of the checksum value produced by the older che...
Definition TClass.cxx:6603
Bool_t HasInterpreterInfo() const
Definition TClass.h:417
void BuildRealData(void *pointer=nullptr, Bool_t isTransient=kFALSE)
Build a full list of persistent data members.
Definition TClass.cxx:2132
TList * GetListOfDataMembers(Bool_t load=kTRUE)
Return list containing the TDataMembers of a class.
Definition TClass.cxx:3867
TList * GetListOfRealData() const
Definition TClass.h:460
Int_t Size() const
Return size of object of this class.
Definition TClass.cxx:5813
Bool_t CanIgnoreTObjectStreamer()
Definition TClass.h:399
const ROOT::Detail::TSchemaRuleSet * GetSchemaRules() const
Return the set of the schema rules if any.
Definition TClass.cxx:2033
TList * GetListOfBases()
Return list containing the TBaseClass(es) of a class.
Definition TClass.cxx:3733
const TObjArray * GetStreamerInfos() const
Definition TClass.h:499
Bool_t IsLoaded() const
Return true if the shared library of this class is currently in the a process's memory.
Definition TClass.cxx:6021
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition TClass.cxx:6047
Bool_t IsForeign() const
Return kTRUE is the class is Foreign (the class does not have a Streamer method).
Definition TClass.cxx:6056
TVirtualStreamerInfo * GetStreamerInfo(Int_t version=0, Bool_t isTransient=kFALSE) const
returns a pointer to the TVirtualStreamerInfo object for version If the object does not exist,...
Definition TClass.cxx:4696
ECheckSum
Definition TClass.h:111
@ kLatestCheckSum
Definition TClass.h:120
@ kNoRange
Definition TClass.h:115
@ kCurrentCheckSum
Definition TClass.h:112
@ kNoBaseCheckSum
Definition TClass.h:119
@ kReflex
Definition TClass.h:117
@ kReflexNoComment
Definition TClass.h:114
@ kWithTypeDef
Definition TClass.h:116
@ kNoRangeCheck
Definition TClass.h:118
@ kNoEnum
Definition TClass.h:113
Int_t GetBaseClassOffset(const TClass *toBase, void *address=nullptr, bool isDerivedObject=true)
Definition TClass.cxx:2892
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition TClass.cxx:2998
Int_t GetClassSize() const
Definition TClass.h:432
Long_t Property() const override
Returns the properties of the TClass as a bit field stored as a Long_t value.
Definition TClass.cxx:6195
@ kInterpreted
Definition TClass.h:129
@ kEmulated
Definition TClass.h:128
@ kNoInfo
Definition TClass.h:125
@ kForwardDeclared
Definition TClass.h:127
Bool_t IsVersioned() const
Definition TClass.h:529
void SetClassSize(Int_t sizof)
Definition TClass.h:310
Version_t GetClassVersion() const
Definition TClass.h:427
TRealData * GetRealData(const char *name) const
Return pointer to TRealData element with name "name".
Definition TClass.cxx:3604
@ kWarned
Definition TClass.h:107
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition TClass.cxx:3069
An array of clone (identical) objects.
static TClass * Class()
static TVirtualCollectionProxy * GenEmulatedProxy(const char *class_name, Bool_t silent)
Generate emulated collection proxy for a given class.
static TClassStreamer * GenEmulatedClassStreamer(const char *class_name, Bool_t silent)
Generate emulated class streamer for a given collection class.
static Proxy_t * GenExplicitProxy(const ::ROOT::TCollectionProxyInfo &info, TClass *cl)
Generate proxy from static functions.
static TClassStreamer * GenExplicitClassStreamer(const ::ROOT::TCollectionProxyInfo &info, TClass *cl)
Generate class streamer from static functions.
virtual Int_t GetEntries() const
Small helper to read a TBuffer containing a TClonesArray into any valid collection.
All ROOT classes may have RTTI (run time type identification) support added.
Definition TDataMember.h:31
Int_t GetMaxIndex(Int_t dim) const
Return maximum index for array dimension "dim".
const char * GetTrueTypeName() const
Get the desugared type name of this data member, including const and volatile qualifiers.
Bool_t IsPersistent() const
Definition TDataMember.h:91
Long_t Property() const override
Get property description word. For meaning of bits see EProperty.
Int_t GetArrayDim() const
Return number of array dimensions.
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:1371
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:47
void Streamer(TBuffer &) override
Stream an object of class TObject.
const char * GetTitle() const override
Returns title of object.
Definition TNamed.h:48
TString fName
Definition TNamed.h:32
static TClass * Class()
virtual void SetName(const char *name)
Set the name of the TNamed.
Definition TNamed.cxx:140
An array of TObjects.
Definition TObjArray.h:31
Int_t GetEntriesFast() const
Definition TObjArray.h:58
void AddAt(TObject *obj, Int_t idx) override
Add object at position ids.
TObject * Last() const override
Return the object in the last filled slot. Returns 0 if no entries.
virtual void AddAtAndExpand(TObject *obj, Int_t idx)
Add object at position idx.
Int_t GetEntries() const override
Return the number of objects in array (i.e.
void Delete(Option_t *option="") override
Remove all objects from the array AND delete all heap based objects.
TObject * At(Int_t idx) const override
Definition TObjArray.h:164
void AddLast(TObject *obj) override
Add object in the next empty slot in the array.
TObject * UncheckedAt(Int_t i) const
Definition TObjArray.h:84
Bool_t IsEmpty() const override
Definition TObjArray.h:65
TObject * FindObject(const char *name) const override
Find an object in this collection using its name.
static TClass * Class()
Int_t GetLast() const override
Return index of last object in array.
void Add(TObject *obj) override
Definition TObjArray.h:68
Collectable string class.
Definition TObjString.h:28
Mother of all ROOT objects.
Definition TObject.h:41
friend class TClonesArray
Definition TObject.h:240
virtual const char * GetName() const
Returns name of object.
Definition TObject.cxx:456
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition TObject.h:199
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:991
static TClass * Class()
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition TObject.cxx:798
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1005
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition TObject.cxx:1033
virtual void ls(Option_t *option="") const
The ls function lists the contents of a class on stdout.
Definition TObject.cxx:591
void ResetBit(UInt_t f)
Definition TObject.h:198
@ kNoContextMenu
if object does not want context menu
Definition TObject.h:69
@ kCanDelete
if object in a list can be deleted
Definition TObject.h:62
void Obsolete(const char *method, const char *asOfVers, const char *removedFromVers) const
Use this method to declare a method obsolete.
Definition TObject.cxx:1067
The TRealData class manages the effective list of all data members for a given class.
Definition TRealData.h:30
const char * GetName() const override
Returns name of object.
Definition TRealData.h:52
static TClass * Class()
void SetNewBaseClass(TClass *cl)
TVirtualStreamerInfo * GetBaseStreamerInfo() const
UInt_t GetBaseCheckSum()
TClass * GetClassPointer() const override
Returns a pointer to the TClass of this element.
static TClass * Class()
static TClass * Class()
static TClass * Class()
virtual TClass * GetClassPointer() const
Returns a pointer to the TClass of this element.
TClass * GetNewClass() const
Int_t GetArrayLength() const
TClass * GetClass() const
static TClass * Class()
void Update(const TClass *oldcl, TClass *newcl)
Update the TClass pointer cached in this object.
TClass * fClass
Not Owned.
TStreamerElement * fElem
Not Owned.
Describes a persistent version of a class.
Int_t fNVirtualInfoLoc
! Number of virtual info location to update.
Int_t fOnFileClassVersion
!Class version identifier as stored on file.
Int_t GetSize() const override
Return total size of all persistent elements of the class (with offsets).
Int_t GetClassVersion() const override
void Destructor(void *p, Bool_t dtorOnly=kFALSE) override
Emulated destructor for this class.
TVirtualStreamerInfo * GenerateInfoForPair(const std::string &pairclassname, bool silent, size_t hint_pair_offset, size_t hint_pair_size) override
Generate the TClass and TStreamerInfo for the requested pair.
TClassStreamer * GenExplicitClassStreamer(const ::ROOT::Detail::TCollectionProxyInfo &info, TClass *cl) override
Generate class streamer from static functions.
TVirtualCollectionProxy * GenEmulatedProxy(const char *class_name, Bool_t silent) override
Generate emulated collection proxy for a given class.
Int_t fNfulldata
!number of elements
TCompInfo * fComp
![fNslots with less than fElements->GetEntries()*1.5 used] Compiled info
TVirtualCollectionProxy * GenExplicitProxy(const ::ROOT::Detail::TCollectionProxyInfo &info, TClass *cl) override
Generate proxy from static functions.
T GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const
Return value of element i in object at pointer.
TStreamerInfoActions::TActionSequence * fWriteMemberWiseVecPtr
! List of write action resulting from the compilation for use in member wise streaming.
TClassStreamer * GenEmulatedClassStreamer(const char *class_name, Bool_t silent) override
Generate emulated class streamer for a given collection class.
Int_t GenerateHeaderFile(const char *dirname, const TList *subClasses=nullptr, const TList *extrainfos=nullptr) override
Generate header file for the class described by this TStreamerInfo the function is called by TFile::M...
TStreamerInfoActions::TActionSequence * fReadText
! List of text read action resulting from the compilation, used for JSON.
void ls(Option_t *option="") const override
List the TStreamerElement list and also the precomputed tables if option contains the string "incOrig...
TCompInfo ** fCompFull
![fElements->GetEntries()]
TObjArray * fElements
Array of TStreamerElements.
void InsertArtificialElements(std::vector< const ROOT::TSchemaRule * > &rules)
Insert new members as expressed in the array of TSchemaRule(s).
Int_t GetOnFileClassVersion() const override
Int_t GetOffset(const char *) const override
Return the offset of the data member as indicated by this StreamerInfo.
void PrintValue(const char *name, char *pointer, Int_t i, Int_t len, Int_t lenmax=1000) const
print value of element i in object at pointer The function may be called in two ways: -method1 len < ...
Int_t GetDataMemberOffset(TDataMember *dm, TMemberStreamer *&streamer) const
Compute data member offset.
TObject * Clone(const char *newname="") const override
Make a clone of an object using the Streamer facility.
T GetTypedValueSTLP(TVirtualCollectionProxy *cont, Int_t i, Int_t j, Int_t k, Int_t eoffset) const
Return value of element i in object number j in a TClonesArray and eventually element k in a sub-arra...
T GetTypedValueSTL(TVirtualCollectionProxy *cont, Int_t i, Int_t j, Int_t k, Int_t eoffset) const
Return value of element i in object number j in a TClonesArray and eventually element k in a sub-arra...
void BuildEmulated(TFile *file) override
Create an Emulation TStreamerInfo object.
void DeleteArray(void *p, Bool_t dtorOnly=kFALSE) override
Destroy an array of emulated objects, with optional delete.
Bool_t BuildFor(const TClass *cl) override
Check if we can build this for foreign class - do we have some rules to do that.
void Build(Bool_t isTransient=kFALSE) override
Build the I/O data structure for the current class version.
void BuildOld() override
rebuild the TStreamerInfo structure
TStreamerInfoActions::TActionSequence * fReadMemberWise
! List of read action resulting from the compilation for use in member wise streaming.
Int_t GetType(Int_t id) const
Int_t fClassVersion
Class version identifier.
Int_t fNdata
!number of optimized elements
void * New(void *obj=nullptr) override
An emulated object is created at address obj, if obj is null we allocate memory for the object.
TStreamerInfo()
Status bits See TVirtualStreamerInfo::EStatusBits for the values.
TStreamerInfoActions::TActionSequence * fReadMemberWiseVecPtr
! List of read action resulting from the compilation for use in member wise streaming.
TStreamerInfoActions::TActionSequence * fReadObjectWise
! List of read action resulting from the compilation.
TClass * GetActualClass(const void *obj) const override
Assuming that obj points to (the part of) an object that is of the type described by this streamerInf...
TStreamerElement * GetStreamerElementReal(Int_t i, Int_t j) const
Obsolete: this routine is obsolete and should not longer be used.
TClass * IsA() const override
TClass * fClass
!pointer to class
Bool_t MatchLegacyCheckSum(UInt_t checksum) const
Return true if the checksum passed as argument is one of the checksum value produced by the older che...
~TStreamerInfo() override
TStreamerInfo dtor.
TCompInfo ** fCompOpt
![fNdata]
void TagFile(TFile *fFile) override
Mark the classindex of the current file as using this TStreamerInfo.
Int_t GetNewType(Int_t id) const
void SetClass(TClass *cl) override
Replace the TClass this streamerInfo is pointing to (belongs to)
UInt_t fCheckSum
Checksum of original class.
void Streamer(TBuffer &) override
Stream an object of class TStreamerInfo.
Int_t GetSizeElements() const
Return total size of all persistent elements of the class use GetSize if you want to get the real siz...
TClass * GetClass() const override
static std::atomic< Int_t > fgCount
Number of TStreamerInfo instances.
T GetTypedValueClones(TClonesArray *clones, Int_t i, Int_t j, Int_t k, Int_t eoffset) const
UInt_t GenerateIncludes(FILE *fp, char *inclist, const TList *extrainfos)
Add to the header file, the #include need for this class.
void ComputeSize()
Compute total size of all persistent elements of the class.
Int_t fNumber
!Unique identifier
void PrintValueSTL(const char *name, TVirtualCollectionProxy *cont, Int_t i, Int_t eoffset, Int_t lenmax=1000) const
Print value of element i in a TClonesArray.
TStreamerInfoActions::TActionSequence * fWriteObjectWise
! List of write action resulting from the compilation.
void CallShowMembers(const void *obj, TMemberInspector &insp, Bool_t isTransient) const override
Emulated a call ShowMembers() on the obj of this class type, passing insp and parent.
void Clear(Option_t *="") override
If opt contains 'built', reset this StreamerInfo as if Build or BuildOld was never called on it (usef...
TObjArray * GetElements() const override
Int_t fSize
!size of the persistent class
static T GetTypedValueAux(Int_t type, void *ladd, int k, Int_t len)
Get the value from inside a collection.
void GenerateDeclaration(FILE *fp, FILE *sfp, const TList *subClasses, Bool_t top=kTRUE)
Write the Declaration of class.
static void PrintValueAux(char *ladd, Int_t atype, TStreamerElement *aElement, Int_t aleng, Int_t *count)
print value of element in object at pointer, type atype, leng aleng or *count The function may be cal...
void * NewArray(Long_t nElements, void *ary=nullptr) override
An array of emulated objects is created at address ary, if ary is null, we allocate memory for the ar...
TStreamerElement * GetStreamerElement(const char *datamember, Int_t &offset) const override
Return the StreamerElement of "datamember" inside our class or any of its base classes.
UInt_t GetCheckSum() const override
void Compile() override
loop on the TStreamerElement list regroup members with same type Store predigested information into l...
void BuildCheck(TFile *file=nullptr, Bool_t load=kTRUE) override
Check if built and consistent with the class dictionary.
Bool_t CompareContent(TClass *cl, TVirtualStreamerInfo *info, Bool_t warn, Bool_t complete, TFile *file) override
Return True if the current StreamerInfo in cl or info is equivalent to this TStreamerInfo.
TStreamerInfoActions::TActionSequence * fWriteMemberWise
! List of write action resulting from the compilation for use in member wise streaming.
Int_t fNslots
!total number of slots in fComp.
void ForceWriteInfo(TFile *file, Bool_t force=kFALSE) override
Recursively mark streamer infos for writing to a file.
Version_t fOldVersion
! Version of the TStreamerInfo object read from the file
static TClass * Class()
void DestructorImpl(void *p, Bool_t dtorOnly)
Internal part of the destructor.
TStreamerInfoActions::TActionSequence * fWriteText
! List of text write action resulting for the compilation, used for JSON.
ULong_t * fVirtualInfoLoc
![fNVirtualInfoLoc] Location of the pointer to the TStreamerInfo inside the object (when emulated)
void Update(const TClass *oldClass, TClass *newClass) override
function called by the TClass constructor when replacing an emulated class by the real class
void PrintValueClones(const char *name, TClonesArray *clones, Int_t i, Int_t eoffset, Int_t lenmax=1000) const
Print value of element i in a TClonesArray.
static TClass * Class()
static TClass * Class()
Basic string class.
Definition TString.h:139
void ToLower()
Change string to lower-case.
Definition TString.cxx:1182
void Clear()
Clear string without changing its capacity.
Definition TString.cxx:1235
const char * Data() const
Definition TString.h:376
@ kTrailing
Definition TString.h:276
TString & Append(const char *cs)
Definition TString.h:572
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
Definition TString.cxx:2378
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition TString.cxx:2356
static TClass * Class()
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:632
virtual const char * BaseName(const char *pathname)
Base name of a file name. Base name of /user/root is root.
Definition TSystem.cxx:934
RAII helper class that ensures that PushProxy() / PopProxy() are called when entering / leaving a C++...
Defines a common interface to inspect/change the contents of an object that represents a collection.
virtual EDataType GetType() const =0
If the value type is a fundamental data type, return its type (see enumeration EDataType).
@ kCustomAlloc
The collection has a custom allocator.
virtual TClass * GetValueClass() const =0
If the value type is a user-defined class, return a pointer to the TClass representing the value type...
virtual Int_t GetCollectionType() const =0
Return the type of the proxied collection (see enumeration TClassEdit::ESTLType)
Abstract Interface class describing Streamer information for one class.
Bool_t fIsBuilt
true if the StreamerInfo has been optimized
std::atomic< Bool_t > fIsCompiled
true if the StreamerInfo has been 'built' (i.e. has all the StreamerElements it should have)
static const char * GetElementCounterStart(const char *dmTitle)
Given a comment/title declaring an array counter, for example:
EReadWrite
EReadWrite Enumerator.
@ kUChar
Equal to TDataType's kchar.
@ kUnsupportedConversion
Type corresponding to a 'missing' data member (with kMissing offset)
static TStreamerBasicType * GetElementCounter(const char *countName, TClass *cl)
Get pointer to a TStreamerBasicType in TClass *cl static function.
virtual TObjArray * GetElements() const =0
TLine * line
std::ostream & Info()
Definition hadd.cxx:171
gr SetName("gr")
@ kSTLbitset
Definition ESTLType.h:37
@ kSTLmap
Definition ESTLType.h:33
@ kSTLunorderedmultiset
Definition ESTLType.h:43
@ kROOTRVec
Definition ESTLType.h:46
@ kSTLset
Definition ESTLType.h:35
@ kSTLmultiset
Definition ESTLType.h:36
@ kSTLvector
Definition ESTLType.h:30
@ kSTLunorderedset
Definition ESTLType.h:42
@ kNotSTL
Definition ESTLType.h:29
@ kSTLmultimap
Definition ESTLType.h:34
void ResetClassVersion(TClass *, const char *, Short_t)
Global function to update the version number.
std::string ResolveTypedef(const char *tname, bool resolveAll=false)
bool IsStdArray(std::string_view name)
Definition TClassEdit.h:183
bool IsStdClass(const char *type)
return true if the class belongs to the std namespace
bool IsStdPair(std::string_view name)
Definition TClassEdit.h:184
std::string GetLong64_Name(const char *original)
Replace 'long long' and 'unsigned long long' by 'Long64_t' and 'ULong64_t'.
ROOT::ESTLType IsSTLCont(std::string_view type)
type : type name: vector<list<classA,allocator>,allocator> result: 0 : not stl container code of cont...
std::string ShortType(const char *typeDesc, int mode)
Return the absolute type of typeDesc.
bool GetStdArrayProperties(const char *typeName, std::string &typeNameBuf, std::array< int, 5 > &maxIndices, int &ndim)
std::string GetNameForIO(const std::string &templateInstanceName, TClassEdit::EModType mode=TClassEdit::kNone, bool *hasChanged=nullptr)
int GetSplit(const char *type, std::vector< std::string > &output, int &nestedLoc, EModType mode=TClassEdit::kNone)
Stores in output (after emptying it) the split type.
@ kDropStlDefault
Definition TClassEdit.h:82
bool IsSTLBitset(const char *type)
Return true is the name is std::bitset<number> or bitset<number>