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