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