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