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