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