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