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