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
60#include "TStreamer.h"
64#include "TInterpreter.h"
65
66#include "TMemberInspector.h"
67
68#include "TMakeProject.h"
69
70#include "TSchemaRuleSet.h"
71#include "TSchemaRule.h"
72
73#include "TVirtualMutex.h"
74
76#include "ROOT/BitUtils.hxx"
77
78#include <cstdio>
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
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
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
124}
125
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 }
135}
136
137enum class EUniquePtrOffset : char
138 {
139 kNA = 0,
140 kZero = 1,
141 kNonZero = 2
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;
163 fOldVersion = Class()->GetClassVersion();
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;
198 fOldVersion = Class()->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 }
276 fInfo->ResetBit(TStreamerInfo::kBuildOldUsed);
277 fInfo->ResetBit(TStreamerInfo::kBuildRunning);
278 }
279 TStreamerInfo* fInfo;
280 };
281
283 {
284 std::string localtypename(s->GetUnderlyingTypeName());
285 Int_t ndim = 0;
286 Int_t totaldim = 0;
288 Int_t datasize = 1;
290 std::vector<Int_t> dimensions;
291 static TClassRef string_classref("string");
293 if (isStdArray) {
294 totaldim = 1;
295 std::array<Int_t, 5> localMaxIndices;
297 for (Int_t i = 0; i < ndim; ++i) {
298 auto d = localMaxIndices[i];
299 dimensions.push_back(d);
300 totaldim *= d;
301 }
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 }
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 &&
368 }
369 if (element->GetType() == TStreamerInfo::kStreamer)
370 memType = element->GetType();
371 return std::make_tuple(memClass, memType, datasize, dimensions, totaldim);
372 }
373
375 {
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()) {
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);
431 Compile();
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
444 TStreamerElement::Class()->IgnoreTObjectStreamer();
445
447
449
451 Bool_t wasCompiled = fComp != 0;
452 ROOT::TSchemaRuleSet::TMatches rules;
453 if (fClass->GetSchemaRules()) {
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.
466 const bool isCollection = fClass->GetCollectionProxy();
467 const bool isString = !strcmp(fClass->GetName(), "string");
468 TBaseClass* base = 0;
470 while ((base = (TBaseClass*)nextb())) {
472 Int_t offset = base->GetDelta();
473 if (offset == kMissing) {
474 continue;
475 }
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 {
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();
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) {
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;
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 }
563 if (offset == kMissing) {
564 continue;
565 }
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
579
580 // Let's treat the unique_ptr case
581 bool 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
596 ndim);
598 while(typeNameBuf.back() == '*') typeNameBuf.pop_back();
599 dmFull = dmType = typeNameBuf.c_str();
600 dt = gROOT->GetType(dmType);
601 }
602
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 //
613 const char* rbracket = ::strchr(dmTitle, ']');
614 if (lbracket && rbracket) {
615 const char* counterName = dm->GetArrayIndex();
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 }
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*"))) {
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]
674 }
675 if (dm->IsEnum()) {
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.",
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)) {
697 } else if (dm->IsSTLContainer()) {
698 TVirtualCollectionProxy *proxy = TClass::GetClass(dmType /* the underlying type */)->GetCollectionProxy();
699 if (proxy)
701 else
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) {
717 if (element->GetClassPointer()->GetCollectionProxy()->GetProperties() & TVirtualCollectionProxy::kIsEmulated) {
718 printErrorMsg("interpreted");
719 delete element;
720 continue;
721 }
722 }
723 }
724 } else {
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()) {
743 } else {
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()) {
753 } else if ((clm == TString::Class()) && !dmIsPtr) {
755 } else {
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;
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 )) ) {
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
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.
819 writecopy->SetNewType( writecopy->GetType() );
820 writecopy->SetOffset( element->GetOffset() );
821 // Put the write element after the read element (that does caching).
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
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);
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);
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);
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);
892 while ((element = (TStreamerElement*) next())) {
893 if (element->TestBit(TStreamerElement::kCache)) {
894 element->SetOffset(infoalloc->GetOffset(element->GetName()));
895 }
896 }
897 }
898
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) {
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");
950 TVirtualCollectionProxy *proxy = clequiv->GetCollectionProxy();
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());
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 {
969 const bool isOldRVec = fClass->GetCollectionType() == ROOT::kROOTRVec && (fElements->GetEntries() == 1) &&
970 !strcmp(fElements->At(0)->GetName(), "fData");
972 // We have a collection that is indeed an STL collection,
973 // we know we don't need its streamerInfo.
975 return;
976 }
977 }
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) {
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");
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());
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
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
1052
1053 } else {
1054 // The class version was not specified when the object was
1055 // written OR it was specified to be 1.
1056
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
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
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
1081
1082 } else {
1083 // The class version was not specified when the object was
1084 // written OR it was specified to be 1.
1085
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 }
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;
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
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.
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)
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.
1202 if (fCheckSum == info->GetCheckSum(TClass::kCurrentCheckSum)
1203 || info->MatchLegacyCheckSum(fCheckSum)
1204 || GetCheckSum(TClass::kCurrentCheckSum) == info->fCheckSum
1205 || MatchLegacyCheckSum(info->GetCheckSum())
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();
1224 TObjArray* elems = info->GetElements();
1225 TStreamerElement* e1 = 0;
1226 TStreamerElement* e2 = 0;
1227 for (Int_t i = 0; i < nel; ++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 {
1241 info = 0;
1242 }
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.",
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.",
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 }
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()
1318 && (fClassVersion != 0) // We don't care about transient classes
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
1329
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)
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 //
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 }
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.
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
1415 && GetCheckSum() != fClass->GetCheckSum()
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.
1421 if (maininfo) {
1422 fNumber = maininfo->GetNumber(); // For ReadStreamerInfo to record the expected slot.
1423 }
1425 return;
1426 }
1427
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
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++) {
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
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 }
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
1552
1553 TIter next(oldClass->GetStreamerInfos());
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
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
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
1603 if (oldContent) {
1604 if (oldContent == newContent) {
1606 } else if (newContent) {
1611 }
1612 } else {
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
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
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
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
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
1755 {
1756 assert(oldClass->GetCollectionProxy() && newClass->GetCollectionProxy());
1757
1758 TVirtualCollectionProxy *old = oldClass->GetCollectionProxy();
1759 TVirtualCollectionProxy *current = newClass->GetCollectionProxy();
1761
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 }
1772 TVirtualStreamerInfo *info = current->GetValueClass()->GetStreamerInfo();
1773 if (info->GetElements()->GetEntriesFast() != 2) {
1774 return oldClass;
1775 }
1776 TStreamerElement *f = (TStreamerElement*) info->GetElements()->At(0);
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;
1800
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) ||
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;
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
1912
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 {
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.
1945 }
1946
1947 TIter next(fElements);
1949 Int_t offset = 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;
1972
1973 //---------------------------------------------------------------------------
1974 // Get schema rules for this class
1975 /////////////////////////////////////////////////////////////////////////////
1976
1977 ROOT::TSchemaRuleSet::TMatches rules;
1979
1980 if (ruleSet) rules = ruleSet->FindRules( GetName(), fOnFileClassVersion, fCheckSum );
1981
1984 fNVirtualInfoLoc = 0;
1985 delete [] fVirtualInfoLoc;
1986 fVirtualInfoLoc = 0;
1987
1988 while ((element = (TStreamerElement*) next())) {
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()) {
2008#if defined(PROPER_IMPLEMEMANTION_OF_BASE_CLASS_RENAMING)
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.
2017#endif
2018
2019 //------------------------------------------------------------------
2020 // We do not have this base class - check if we're renaming
2021 ////////////////////////////////////////////////////////////////////
2022
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();
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.
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.
2073 if (listOfBases) {
2074 TBaseClass* bc = 0;
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()) {
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.
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 {
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);
2118 if (store) {
2120 delete [] store;
2121 }
2122 }
2123 for (int nloc = 0; nloc < infobase->fNVirtualInfoLoc; ++nloc) {
2124 fVirtualInfoLoc[ fNVirtualInfoLoc + nloc ] = baseOffset + infobase->fVirtualInfoLoc[nloc];
2125 }
2126 fNVirtualInfoLoc += infobase->fNVirtualInfoLoc;
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.
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++;
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;
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()
2178 && bc->GetClassPointer()->GetCollectionProxy()->GetCollectionType() != ROOT::kSTLvector) {
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
2192 if (newInfo == this) {
2194 asize = element->GetSize();
2195 } else if (newInfo) {
2196 TIter newElems( newInfo->GetElements() );
2198 while( (newElement = (TStreamerElement*)newElems()) ) {
2199 const char *newElName = newElement->GetName();
2200 if (newElement->IsBase() && (strchr(newElName,'<') || !strcmp(newElName,"string")) ) {
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();
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.
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.
2254 fNVirtualInfoLoc = 1;
2255 fVirtualInfoLoc = new ULong_t[1]; // To allow for a single delete statement.
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
2270
2271 // First set the offset and sizes.
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
2288 if (dm && dm->IsPersistent()) {
2290 streamer = 0;
2292 element->SetOffset(offset);
2293 element->Init(this);
2294
2295 // Treat unique pointers and std arrays
2296 dmType = dm->GetTypeName();
2297 dmIsPtr = dm->IsaPointer();
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
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.
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()
2325 && elemDm->GetCollectionProxy()->GetCollectionType() != ROOT::kSTLvector) {
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()) {
2359 pattern->GetStreamerElement(element->GetName(), pair_element_offset);
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.
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;
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) {
2408 } else if (dmIsPtr) {
2409 newType += kOffsetP;
2410 } else if (isArray) {
2411 newType += kOffsetL;
2412 }
2413 }
2414 if (newType == -1) {
2416 }
2417 } else {
2418 // Either the class is not loaded or the data member is gone
2419 if (!fClass->IsLoaded()) {
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();
2478 element->Update(oldClass, newClass.GetClass());
2479 TVirtualCollectionProxy *cp = newClass->GetCollectionProxy();
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 {
2502 }
2503 }
2505 Int_t oldkind = oldClass->GetCollectionType();
2506 Int_t newkind = newClass->GetCollectionType();
2507
2510
2511 Int_t elemType = element->GetType();
2513
2514 TClassStreamer *streamer2 = newClass->GetStreamer();
2515 if (streamer2) {
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) &&
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 }
2548 // Actually nothing to do, since both are the same collection of double in memory.
2550 // Actually nothing to do, since both are the same collection of double in memory.
2552 // Not much to do since both are the same collection of 8 bits entities on file.
2553 element->Update(oldClass, newClass.GetClass());
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..)
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()) {
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)
2634 {
2636
2637 } else if (element->GetType() == kSTLp || ((element->GetType() == kObjectP || element->GetType() == kAnyP) && oldClass == TClonesArray::Class()) )
2638 {
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)
2644 {
2646
2647 } else if (element->GetType() == kSTLp + kOffsetL || ((element->GetType() == kObjectP+ kOffsetL || element->GetType() == kAnyP+ kOffsetL) && oldClass == TClonesArray::Class()) )
2648 {
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.
2665 }
2666 } else {
2667 // We have no clue
2668 printf("%s We have no clue\n", dm->GetName());
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 {
2677 }
2678 } else {
2679 // We have no clue
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
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 &&
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();
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) {
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);
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();
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.
2775 next(); // move the cursor passed the insert object.
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).
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.
2829 offset += sizeof(TStreamerInfo*);
2830 }
2831
2832 // change order , move "bazes" to the end. Workaround old bug
2833 if ((fOldVersion <= 2) && 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) {
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).
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
2901 if (fReadText) fReadText->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)) {
2987 if (name != othername) {
2990 if (!CollectionMatch(cl,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
3010{
3011 TIter next(fElements);
3013
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
3076{
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()) {
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{
3114 R__ASSERT( (cl==0 || info==0) && (cl!=0 || info!=0) /* must compare to only one thing! */);
3115
3116 TString name;
3117 TString type;
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;
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) {
3154 if (tbc) {
3155 otherClass = tbc->GetName();
3156 } else if (el==0) {
3157 done = kTRUE;
3158 break;
3159 }
3160 } else {
3162 if (infoel && infoel->IsBase()) {
3163 otherClass = infoel->GetName();
3164 } else if (el==0) {
3165 done = kTRUE;
3166 break;
3167 }
3168 }
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.",
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",
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'",
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());
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 );
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());
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());
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) {
3315 while(tdm && ( (!tdm->IsPersistent()) || (tdm->Property()&kIsStatic) || (el && local.fName != tdm->GetName()) )) {
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) {
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 {
3344 while (infoel && (infoel->IsBase() || infoel->IsA() == TStreamerArtificial::Class())) {
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()) {
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
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()) {
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
3468 {
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.
3501 if (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);
3514 for (; element; element = (TStreamerElement*) next()) {
3515 if (element->IsTransient()) continue;
3516 TClass* cl = element->GetClassPointer();
3517 if (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{
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());
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.
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:
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.
3630 type = TClassEdit::ResolveTypedef(el->GetTypeName(),kTRUE);
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 }
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{
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 }
3702 if (TVirtualStreamerInfo::kOffsetP <= element->GetType() && element->GetType() < TVirtualStreamerInfo::kObject ) {
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
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
3731{
3733 next.Reset();
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);
3756 } else if (TVirtualStreamerInfo::kOffsetP <= element->GetType() && element->GetType() < TVirtualStreamerInfo::kObject ) {
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{
3798 next.Reset();
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
3823}
3824
3825////////////////////////////////////////////////////////////////////////////////
3826/// Write down the body of the 'move' constructor.
3827
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
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
3852
3853 fprintf(file, " return *this;\n");
3854}
3855
3856////////////////////////////////////////////////////////////////////////////////
3857
3858static void R__WriteDestructorBody(FILE *file, TIter &next)
3859{
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 }
3892 if (TVirtualStreamerInfo::kOffsetP <= element->GetType() && element->GetType() < TVirtualStreamerInfo::kObject ) {
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 {
3924 std::vector<std::string> inside;
3925 int nestedLoc;
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
3945{
3946 if (fClassVersion == -3) {
3947 return;
3948 }
3949
3952 const char *clname = GetName();
3954 if (strchr(clname, ':')) {
3955 // We might have a namespace in front of the classname.
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
3975 name = clname + cur + 2;
3976 }
3977 break;
3978 }
3979 }
3980 }
3981 if (isTemplate) {
3983 }
3984 clname = name;
3985 } else {
3986 const char *where = strstr(clname, "<");
3987 isTemplate = where != 0;
3988 if (isTemplate) {
3990 }
3991 }
3992
3995 fprintf(fp, "#ifndef %s_h\n", templateName.Data());
3996 fprintf(fp, "#define %s_h\n", templateName.Data());
3997 }
3998
4001
4002 // Generate class statement with base classes.
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
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 }
4033 if (subinfo->GetClassVersion() == -3) {
4035 } else {
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()) {
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 {
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) {
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 }
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());
4144 fprintf(fp," }\n");
4145 fprintf(fp," %s(const %s & rhs )\n ",protoname.Data(),protoname.Data());
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());
4166 fprintf(sfp,"}\n");
4167
4168 fprintf(sfp,"%s &%s::operator=(const %s & rhs)\n",GetName(),GetName(),protoname.Data());
4170 fprintf(sfp,"}\n");
4171
4172 fprintf(sfp,"%s::%s(const %s & rhs)\n",GetName(),protoname.Data(),protoname.Data());
4174 fprintf(sfp,"}\n");
4175
4176 fprintf(sfp,"%s::~%s() {\n",GetName(),protoname.Data());
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
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
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.
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);
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 streaming classes in case of an STL container
4247 if (!incRiostream && element->InheritsFrom(TStreamerSTL::Class())) {
4249#ifdef __APPLE__
4250 // Workaround for https://github.com/llvm/llvm-project/issues/138683
4251 // Include <chrono> before <fstream> to ensure _FilesystemClock is defined
4252 // Can be removed once the upstream issue is fixed.
4253 TMakeProject::AddInclude( fp, "chrono", kTRUE, inclist);
4254#endif
4255 TMakeProject::AddInclude( fp, "fstream", kTRUE, inclist);
4256 TMakeProject::AddInclude( fp, "iostream", kTRUE, inclist);
4257 TMakeProject::AddInclude( fp, "iomanip", kTRUE, inclist);
4258 }
4259
4260 //get include file name if any
4261 const char *include = element->GetInclude();
4262 if (!include[0]) continue;
4263
4264 Bool_t greater = (include[0]=='<');
4265 include++;
4266
4267 if (strncmp(include,"include/",8)==0) {
4268 include += 8;
4269 }
4270 if (strncmp(include,"include\\",9)==0) {
4271 include += 9;
4272 }
4273 if (TClassEdit::IsStdPair(element->GetTypeName())) {
4274 TMakeProject::AddInclude( fp, "utility", kTRUE, inclist);
4275 } else if (strncmp(element->GetTypeName(),"auto_ptr<",std::char_traits<char>::length("auto_ptr<"))==0) {
4276 TMakeProject::AddInclude( fp, "memory", kTRUE, inclist);
4277 } else {
4281 }
4282
4283 if (strchr(element->GetTypeName(),'<')) {
4284 // This is a template, we need to check the template parameter.
4286 }
4287 }
4288 return ninc;
4289}
4290
4291////////////////////////////////////////////////////////////////////////////////
4292/// Generate header file for the class described by this TStreamerInfo
4293/// the function is called by TFile::MakeProject for each class in the file
4294
4296{
4297 // if (fClassVersion == -4) return 0;
4298 if ((fClass && fClass->GetCollectionType()) || TClassEdit::IsSTLCont(GetName())) return 0;
4299 if (TClassEdit::IsStdPair(GetName())) return 0;
4300 if (strncmp(GetName(),"auto_ptr<",std::char_traits<char>::length("auto_ptr<"))==0) return 0;
4301
4303 if (cl) {
4304 if (cl->HasInterpreterInfo()) return 0; // skip known classes
4305 }
4307 if (strchr(GetName(),':')) {
4308 UInt_t len = strlen(GetName());
4309 UInt_t nest = 0;
4310 UInt_t scope = 0;
4311 for(UInt_t i=len; i>0; --i) {
4312 switch(GetName()[i]) {
4313 case '>': ++nest; if (scope==0) { isTemplate = kTRUE; } break;
4314 case '<': --nest; break;
4315 case ':':
4316 if (nest==0 && GetName()[i-1]==':') {
4317 // We have a scope
4318 TString nsname(GetName(), i-1);
4319 cl = gROOT->GetClass(nsname);
4320 if (cl && (cl->Size()!=0 || (cl->Size()==0 && !cl->HasInterpreterInfo() /*empty 'base' class on file*/))) {
4321 // This class is actually nested.
4322 return 0;
4323 } else if (cl == 0 && extrainfos != 0) {
4325 if (clinfo && clinfo->GetClassVersion() == -5) {
4326 // This class is actually nested.
4327 return 0;
4328 }
4329 }
4330 ++scope;
4331 }
4332 break;
4333 }
4334 }
4335 }
4337
4338 if (gDebug) printf("generating code for class %s\n",GetName());
4339
4340 // Open the file
4341
4344 filename.Form("%s/%s.h",dirname,headername.Data());
4345
4346 FILE *fp = fopen(filename.Data(),"w");
4347 if (!fp) {
4348 Error("MakeProject","Cannot open output file:%s\n",filename.Data());
4349 return 0;
4350 }
4351
4352 filename.Form("%s/%sProjectHeaders.h",dirname,gSystem->BaseName(dirname));
4353 FILE *allfp = fopen(filename.Data(),"a");
4354 if (!allfp) {
4355 Error("MakeProject","Cannot open output file:%s\n",filename.Data());
4356 fclose(fp);
4357 return 0;
4358 }
4359 fprintf(allfp,"#include \"%s.h\"\n", headername.Data());
4360 fclose(allfp);
4361
4362 char *inclist = new char[50000];
4363 inclist[0] = 0;
4364
4365 // Generate class header.
4366 TDatime td;
4367 fprintf(fp,"//////////////////////////////////////////////////////////\n");
4368 fprintf(fp,"// This class has been generated by TFile::MakeProject\n");
4369 fprintf(fp,"// (%s by ROOT version %s)\n",td.AsString(),gROOT->GetVersion());
4370 fprintf(fp,"// from the StreamerInfo in file %s\n",gDirectory->GetFile()->GetName());
4371 fprintf(fp,"//////////////////////////////////////////////////////////\n");
4372 fprintf(fp,"\n");
4373 fprintf(fp,"\n");
4374 fprintf(fp,"#ifndef %s_h\n",headername.Data());
4375 fprintf(fp,"#define %s_h\n",headername.Data());
4377 fprintf(fp,"\n");
4378
4380 if (subClasses) {
4383 while ((subinfo = (TStreamerInfo*)subnext())) {
4384 subinfo->GenerateIncludes(fp, inclist, extrainfos);
4385 }
4386 }
4387 fprintf(fp,"\n");
4388
4389 TString sourcename; sourcename.Form( "%s/%sProjectSource.cxx", dirname, gSystem->BaseName(dirname) );
4390 FILE *sfp = fopen( sourcename.Data(), "a" );
4391 if (sfp) {
4393 } else {
4394 Error("GenerateHeaderFile","Could not open %s for appending",sourcename.Data());
4395 }
4397
4398 fprintf(fp,"#endif\n");
4399
4400 delete [] inclist;
4401 fclose(fp);
4402 if (sfp) fclose(sfp);
4403 return 1;
4404}
4405
4406////////////////////////////////////////////////////////////////////////////////
4407/// Compute data member offset.
4408/// Return pointer to the Streamer function if one exists
4409
4411{
4413 char dmbracket[256];
4414 snprintf(dmbracket,255,"%s[",dm->GetName());
4416 if (!fClass->IsLoaded()) {
4417 // If the 'class' is not loaded, we do not have a TClass bootstrap and thus
4418 // the 'RealData' might not have enough information because of the lack
4419 // of proper ShowMember implementation.
4420 if (! (dm->Property() & kIsStatic) ) {
4421 // Give an offset only to non-static members.
4422 offset = dm->GetOffset();
4423 }
4424 }
4425 TRealData *rdm;
4426 while ((rdm = (TRealData*)nextr())) {
4427 char *rdmc = (char*)rdm->GetName();
4428 //next statement required in case a class and one of its parent class
4429 //have data members with the same name
4430 if (dm->IsaPointer() && rdmc[0] == '*') rdmc++;
4431
4432 if (rdm->GetDataMember() != dm) continue;
4433 if (strcmp(rdmc,dm->GetName()) == 0) {
4434 offset = rdm->GetThisOffset();
4435 streamer = rdm->GetStreamer();
4436 break;
4437 }
4438 if (strcmp(rdm->GetName(),dm->GetName()) == 0) {
4439 if (rdm->IsObject()) {
4440 offset = rdm->GetThisOffset();
4441 streamer = rdm->GetStreamer();
4442 break;
4443 }
4444 }
4445 if (strstr(rdm->GetName(),dmbracket)) {
4446 offset = rdm->GetThisOffset();
4447 streamer = rdm->GetStreamer();
4448 break;
4449 }
4450 }
4451 return offset;
4452}
4453
4454////////////////////////////////////////////////////////////////////////////////
4455/// Return the offset of the data member as indicated by this StreamerInfo.
4456
4458{
4459 if (elementName == 0) return 0;
4460
4461 Int_t offset = 0;
4463 if (elem) offset = elem->GetOffset();
4464
4465 return offset;
4466}
4467
4468////////////////////////////////////////////////////////////////////////////////
4469/// Return total size of all persistent elements of the class (with offsets).
4470
4472{
4473 return fSize;
4474}
4475
4476////////////////////////////////////////////////////////////////////////////////
4477/// Return total size of all persistent elements of the class
4478/// use GetSize if you want to get the real size in memory.
4479
4481{
4482 TIter next(fElements);
4484 Int_t asize = 0;
4485 while ((element = (TStreamerElement*)next())) {
4486 asize += element->GetSize();
4487 }
4488 return asize;
4489}
4490
4491////////////////////////////////////////////////////////////////////////////////
4492/// Return the StreamerElement of "datamember" inside our
4493/// class or any of its base classes.
4494///
4495/// The offset information
4496/// contained in the StreamerElement is related to its immediately
4497/// containing class, so we return in 'offset' the offset inside
4498/// our class.
4499
4501{
4502 if (!fElements) {
4503 return 0;
4504 }
4505
4506 // Look first at the data members and base classes
4507 // of our class.
4509 if (element) {
4510 offset = element->GetOffset();
4511 return element;
4512 }
4513
4514 // Not found, so now try the data members and base classes
4515 // of the base classes of our class.
4516 if (fClass->HasDataMemberInfo()) {
4517 // Our class has a dictionary loaded, use it to search the base classes.
4519 TBaseClass* base = 0;
4520 TClass* base_cl = 0;
4521 Int_t base_offset = 0;
4522 Int_t local_offset = 0;
4524 // Iterate on list of base classes.
4525 while ((base = (TBaseClass*) nextb())) {
4526 base_cl = TClass::GetClass(base->GetName());
4528 if (!base_cl || !base_element) {
4529 continue;
4530 }
4531 base_offset = base_element->GetOffset();
4533 if (element) {
4535 return element;
4536 }
4537 }
4538 } else {
4539 // Our class's dictionary is not loaded. Search through the base class streamer elements.
4540 TIter next(fElements);
4542 while ((curelem = (TStreamerElement*) next())) {
4543 if (curelem->InheritsFrom(TStreamerBase::Class())) {
4544 TClass* baseClass = curelem->GetClassPointer();
4545 if (!baseClass) {
4546 continue;
4547 }
4548 Int_t base_offset = curelem->GetOffset();
4549 Int_t local_offset = 0;
4551 if (baseClass->Property() & kIsAbstract) {
4552 baseInfo = (TStreamerInfo*)baseClass->GetStreamerInfoAbstractEmulated();
4553 } else {
4554 baseInfo = (TStreamerInfo*)baseClass->GetStreamerInfo();
4555 }
4556 if (baseInfo) element = baseInfo->GetStreamerElement(datamember, local_offset);
4557 if (element) {
4559 return element;
4560 }
4561 }
4562 }
4563 }
4564 return 0;
4565}
4566
4567////////////////////////////////////////////////////////////////////////////////
4568/// <b>Obsolete</b>: this routine is obsolete and should not longer be used.
4569///
4570/// TStreamerInfo holds two types of data structures
4571/// - TObjArray* fElements; containing the list of all TStreamerElement
4572/// objects for this class version.
4573/// - ULong_t* fElem; containing the preprocessed information
4574/// by TStreamerInfo::Compile In case consecutive data members
4575/// are of the same type, the Compile function declares the consecutive
4576/// elements as one single element in fElems.
4577///
4578/// Example with the class TAttLine:
4579/// ~~~{.cpp}
4580/// TClass::GetClass("TAttLine")->GetStreamerInfo()->ls(); produces;
4581/// StreamerInfo for class: TAttLine, version=1
4582/// short fLineColor offset= 4 type= 2 line color
4583/// short fLineStyle offset= 6 type= 2 line style
4584/// short fLineWidth offset= 8 type= 2 line width
4585/// i= 0, fLineColor type= 22, offset= 4, len=3, method=0
4586/// ~~~
4587/// For I/O implementations (eg. XML) , one has to know the original name
4588/// of the data member. This function can be used to return a pointer
4589/// to the original TStreamerElement object corresponding to the j-th
4590/// element of a compressed array in fElems.
4591/// Parameters description:
4592/// - i: the serial number in array fElem
4593/// - j: the element number in the array of consecutive types
4594/// In the above example the class TAttLine has 3 consecutive data members
4595/// of the same type "short". Compile makes one single array of 3 elements.
4596/// To access the TStreamerElement for the second element
4597/// of this array, one can call:
4598/// ~~~{.cpp}
4599/// auto el = GetStreamerElementReal(0,1);
4600/// auto membername = el->GetName();
4601/// ~~~
4602/// This function is typically called from TBuffer, TXmlBuffer.
4603
4605{
4606 ::Obsolete("TStreamerInfo::GetStreamerElementReal", "v5-34-20", "v6-00-02");
4607
4608 if (i < 0 || i >= fNdata) return 0;
4609 if (j < 0) return 0;
4610 if (!fElements) return 0;
4612 if (!se) return 0;
4614 for (Int_t ise=0;ise < nelems;ise++) {
4615 if (se != (TStreamerElement*)fElements->UncheckedAt(ise)) continue;
4616 if (ise+j >= nelems) return 0;
4618 }
4619 return 0;
4620}
4621
4622////////////////////////////////////////////////////////////////////////////////
4623/// Get the value from inside a collection.
4624
4625template <typename T>
4627{
4628 if (type>=kConv && type<kSTL) {
4629 type -= kConv;
4630 }
4631 switch (type) {
4632 // basic types
4633 case kBool: {Bool_t *val = (Bool_t*)ladd; return T(*val);}
4634 case kChar: {Char_t *val = (Char_t*)ladd; return T(*val);}
4635 case kShort: {Short_t *val = (Short_t*)ladd; return T(*val);}
4636 case kInt: {Int_t *val = (Int_t*)ladd; return T(*val);}
4637 case kLong: {Long_t *val = (Long_t*)ladd; return T(*val);}
4638 case kLong64: {Long64_t *val = (Long64_t*)ladd; return T(*val);}
4639 case kFloat: {Float_t *val = (Float_t*)ladd; return T(*val);}
4640 case kFloat16: {Float_t *val = (Float_t*)ladd; return T(*val);}
4641 case kDouble: {Double_t *val = (Double_t*)ladd; return T(*val);}
4642 case kDouble32: {Double_t *val = (Double_t*)ladd; return T(*val);}
4643 case kUChar: {UChar_t *val = (UChar_t*)ladd; return T(*val);}
4644 case kUShort: {UShort_t *val = (UShort_t*)ladd; return T(*val);}
4645 case kUInt: {UInt_t *val = (UInt_t*)ladd; return T(*val);}
4646 case kULong: {ULong_t *val = (ULong_t*)ladd; return T(*val);}
4647#if defined(_MSC_VER) && (_MSC_VER <= 1200)
4648 case kULong64: {Long64_t *val = (Long64_t*)ladd; return T(*val);}
4649#else
4650 case kULong64: {ULong64_t *val= (ULong64_t*)ladd; return T(*val);}
4651#endif
4652 case kBits: {UInt_t *val = (UInt_t*)ladd; return T(*val);}
4653
4654 // array of basic types array[8]
4655 case kOffsetL + kBool: {Bool_t *val = (Bool_t*)ladd; return T(val[k]);}
4656 case kOffsetL + kChar: {Char_t *val = (Char_t*)ladd; return T(val[k]);}
4657 case kOffsetL + kShort: {Short_t *val = (Short_t*)ladd; return T(val[k]);}
4658 case kOffsetL + kInt: {Int_t *val = (Int_t*)ladd; return T(val[k]);}
4659 case kOffsetL + kLong: {Long_t *val = (Long_t*)ladd; return T(val[k]);}
4660 case kOffsetL + kLong64: {Long64_t *val = (Long64_t*)ladd; return T(val[k]);}
4661 case kOffsetL + kFloat: {Float_t *val = (Float_t*)ladd; return T(val[k]);}
4662 case kOffsetL + kFloat16: {Float_t *val = (Float_t*)ladd; return T(val[k]);}
4663 case kOffsetL + kDouble: {Double_t *val = (Double_t*)ladd; return T(val[k]);}
4664 case kOffsetL + kDouble32:{Double_t *val = (Double_t*)ladd; return T(val[k]);}
4665 case kOffsetL + kUChar: {UChar_t *val = (UChar_t*)ladd; return T(val[k]);}
4666 case kOffsetL + kUShort: {UShort_t *val = (UShort_t*)ladd; return T(val[k]);}
4667 case kOffsetL + kUInt: {UInt_t *val = (UInt_t*)ladd; return T(val[k]);}
4668 case kOffsetL + kULong: {ULong_t *val = (ULong_t*)ladd; return T(val[k]);}
4669#if defined(_MSC_VER) && (_MSC_VER <= 1200)
4670 case kOffsetL + kULong64: {Long64_t *val = (Long64_t*)ladd; return T(val[k]);}
4671#else
4672 case kOffsetL + kULong64:{ULong64_t *val= (ULong64_t*)ladd; return T(val[k]);}
4673#endif
4674
4675#define READ_ARRAY(TYPE_t) \
4676 { \
4677 Int_t sub_instance, index; \
4678 Int_t instance = k; \
4679 if (len) { \
4680 index = instance / len; \
4681 sub_instance = instance % len; \
4682 } else { \
4683 index = instance; \
4684 sub_instance = 0; \
4685 } \
4686 TYPE_t **val =(TYPE_t**)(ladd); \
4687 return T((val[sub_instance])[index]); \
4688 }
4689
4690 // pointer to an array of basic types array[n]
4691 case (unsigned)kOffsetP + kBool_t: READ_ARRAY(Bool_t)
4692 case (unsigned)kOffsetP + kChar_t: READ_ARRAY(Char_t)
4693 case (unsigned)kOffsetP + kShort_t: READ_ARRAY(Short_t)
4694 case (unsigned)kOffsetP + kInt_t: READ_ARRAY(Int_t)
4695 case (unsigned)kOffsetP + kLong_t: READ_ARRAY(Long_t)
4696 case (unsigned)kOffsetP + kLong64_t: READ_ARRAY(Long64_t)
4697 case (unsigned)kOffsetP + kFloat16_t:
4698 case (unsigned)kOffsetP + kFloat_t: READ_ARRAY(Float_t)
4699 case (unsigned)kOffsetP + kDouble32_t:
4700 case (unsigned)kOffsetP + kDouble_t: READ_ARRAY(Double_t)
4701 case (unsigned)kOffsetP + kUChar_t: READ_ARRAY(UChar_t)
4702 case (unsigned)kOffsetP + kUShort_t: READ_ARRAY(UShort_t)
4703 case (unsigned)kOffsetP + kUInt_t: READ_ARRAY(UInt_t)
4704 case (unsigned)kOffsetP + kULong_t: READ_ARRAY(ULong_t)
4705#if defined(_MSC_VER) && (_MSC_VER <= 1200)
4706 case (unsigned)kOffsetP + kULong64_t: READ_ARRAY(Long64_t)
4707#else
4708 case (unsigned)kOffsetP + kULong64_t: READ_ARRAY(ULong64_t)
4709#endif
4710
4711 // array counter //[n]
4712 case kCounter: {Int_t *val = (Int_t*)ladd; return T(*val);}
4713 }
4714 return 0;
4715}
4716
4717
4718
4719template Double_t TStreamerInfo::GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const;
4720template Long64_t TStreamerInfo::GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const;
4721template LongDouble_t TStreamerInfo::GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const;
4722
4723////////////////////////////////////////////////////////////////////////////////
4724/// Return value of element i in object at pointer.
4725/// The function may be called in two ways:
4726/// - method1 len < 0: i is assumed to be the TStreamerElement number i in StreamerInfo
4727/// - method2 len >= 0: i is the type, address of variable is directly pointer.
4728
4729template <typename T>
4731{
4732 char *ladd;
4733 Int_t atype;
4734 if (len >= 0) {
4735 ladd = pointer;
4736 atype = i;
4737 } else {
4738 if (i < 0) return 0;
4739 ladd = pointer + fCompFull[i]->fOffset;
4740 atype = fCompFull[i]->fNewType;
4742 if (atype == kSTL) {
4744 if (newClass == 0) {
4746 }
4747 TClass *innerClass = newClass->GetCollectionProxy()->GetValueClass();
4748 if (innerClass) {
4749 return 0; // We don't know which member of the class we would want.
4750 } else {
4751 TVirtualCollectionProxy *proxy = newClass->GetCollectionProxy();
4752 // EDataType is a subset of TStreamerInfo::EReadWrite
4755 Int_t nc = proxy->Size();
4756 if (j >= nc) return 0;
4757 char *element_ptr = (char*)proxy->At(j);
4759 }
4760 }
4761 }
4763}
4764
4765////////////////////////////////////////////////////////////////////////////////
4766
4767template Double_t TStreamerInfo::GetTypedValueClones<Double_t>(TClonesArray *clones, Int_t i, Int_t j, int k, Int_t eoffset) const;
4770
4771template <typename T>
4773{
4774 // return value of element i in object number j in a TClonesArray and eventually
4775 // element k in a sub-array.
4776
4777 Int_t nc = clones->GetEntriesFast();
4778 if (j >= nc) return 0;
4779
4780 char *pointer = (char*)clones->UncheckedAt(j);
4781 char *ladd = pointer + eoffset + fCompFull[i]->fOffset;
4782 return GetTypedValueAux<T>(fCompFull[i]->fType,ladd,k,((TStreamerElement*)fCompFull[i]->fElem)->GetArrayLength());
4783}
4784
4788
4789////////////////////////////////////////////////////////////////////////////////
4790/// Return value of element i in object number j in an STL container and eventually
4791/// element k in a sub-array.
4792
4793template <typename T>
4795{
4796 Int_t nc = cont->Size();
4797 if (j >= nc) return 0;
4798
4799 char *pointer = (char*)cont->At(j);
4800 char *ladd = pointer + eoffset + fCompFull[i]->fOffset;
4801 return GetTypedValueAux<T>(fCompFull[i]->fType,ladd,k,((TStreamerElement*)fCompFull[i]->fElem)->GetArrayLength());
4802}
4803
4807
4808////////////////////////////////////////////////////////////////////////////////
4809/// Return value of element i in object number j in a pointer to STL container and eventually
4810/// element k in a sub-array.
4811
4812template <typename T>
4814{
4815 Int_t nc = cont->Size();
4816
4817 if (j >= nc) return 0;
4818
4819 char **ptr = (char**)cont->At(j);
4820 char *pointer = *ptr;
4821
4822 char *ladd = pointer + eoffset + fCompFull[i]->fOffset;
4823 return GetTypedValueAux<T>(fCompFull[i]->fType,ladd,k,((TStreamerElement*)fCompFull[i]->fElem)->GetArrayLength());
4824}
4825
4826////////////////////////////////////////////////////////////////////////////////
4827/// Insert new members as expressed in the array of TSchemaRule(s).
4828
4829void TStreamerInfo::InsertArtificialElements(std::vector<const ROOT::TSchemaRule*> &rules)
4830{
4831 if (rules.empty()) return;
4832
4833 TIter next(fElements);
4834 UInt_t count = 0;
4835
4836 for(auto rule : rules) {
4837 if( rule->IsRenameRule() || rule->IsAliasRule() )
4838 continue;
4839 next.Reset();
4841 while ((element = (TStreamerElement*) next())) {
4842 if ( rule->HasTarget( element->GetName() ) ) {
4843
4844 // Check whether this is an 'attribute' rule.
4845 if ( rule->GetAttributes()[0] != 0 ) {
4846 TString attr( rule->GetAttributes() );
4847 attr.ToLower();
4848 if (attr.Contains("owner")) {
4849 if (attr.Contains("notowner")) {
4851 } else {
4853 }
4854 }
4855
4856 }
4857 break;
4858 }
4859 }
4860
4861 auto canIgnore = [](const ROOT::TSchemaRule *r) {
4862 if (r->GetAttributes()[0] != 0) {
4863 TString attr(r->GetAttributes());
4864 attr.ToLower();
4865 return attr.Contains("canignore");
4866 } else
4867 return false;
4868 };
4869 // NOTE: Before adding the rule we should check that the source do
4870 // existing in this StreamerInfo.
4871 const TObjArray *sources = rule->GetSource();
4872 if (sources)
4874 auto source_element = dynamic_cast<TStreamerElement *>(GetElements()->FindObject(src->GetName()));
4875 if (!source_element) {
4876 // It might still be in one the base classes.
4877 if (fClass->GetListOfRealData() && !fClass->GetListOfRealData()->FindObject(src->GetName())) {
4878 // Missing source.
4879 if (!canIgnore(rule)) {
4881 rule->AsString(ruleStr);
4882 Warning("InsertArtificialElements",
4883 "For class %s in StreamerInfo %d is missing the source data member `%s` when trying to "
4884 "apply the "
4885 "rule:\n %s",
4886 GetName(), GetClassVersion(), src->GetName(), ruleStr.Data());
4887 }
4888 rule = nullptr;
4889 break;
4890 }
4891 } else {
4892 // The source exists, let's check if it has the expected type.
4894 if ((memClass != source_element->GetNewClass() || memType != source_element->GetNewType()) &&
4896 const char *dim = src->GetDimensions();
4898 rule->AsString(ruleStr);
4899 auto cl = source_element->GetNewClass();
4901 if (memClass != cl) {
4902 classmsg = "and the memory TClass is \"";
4903 classmsg += cl ? cl->GetName() : "nullptr";
4904 classmsg += "\" while the rule needed \"";
4905 classmsg += memClass ? memClass->GetName() : "nullptr";
4906 classmsg += "\"";
4907 }
4908 Error("InsertArtificialElements",
4909 "For class %s in StreamerInfo %d a rule has conflicting type for the source \"%s %s%s\",\n"
4910 " The TStreamerElement has memory type %d (needed %d) %s:\n %s",
4911 GetName(), GetClassVersion(), src->GetTypeForDeclaration().Data(), src->GetName(),
4912 dim && dim[0] ? dim : "", source_element->GetNewType(), memType, classmsg.Data(),
4913 ruleStr.Data());
4914 rule = nullptr;
4915 break;
4916 }
4917 }
4918 }
4919
4920 if (!rule) continue;
4921
4923 std::vector<TStreamerArtificial*> toAdd;
4924
4925 if (rule->GetTarget()==0) {
4927 newName.Form("%s_rule%d",fClass->GetName(),count);
4931 "void");
4933 newel->SetReadFunc( rule->GetReadFunctionPointer() );
4934 newel->SetReadRawFunc( rule->GetReadRawFunctionPointer() );
4935 toAdd.push_back(newel);
4936 } else {
4937 toAdd.reserve(rule->GetTarget()->GetEntriesFast());
4938 TObjString * objstr = (TObjString*)(rule->GetTarget()->At(0));
4939 if (objstr) {
4940 TString newName = objstr->String();
4942 if ( TDataMember* dm = fClass->GetDataMember( newName ) ) {
4945 TStreamerInfo::kArtificial, dm->GetTypeName());
4946 newel->SetReadFunc( rule->GetReadFunctionPointer() );
4947 newel->SetReadRawFunc( rule->GetReadRawFunctionPointer() );
4948 toAdd.push_back(newel);
4949 } else {
4950 // This would be a completely new member (so it would need to be cached)
4951 // TOBEDONE
4952 }
4953 for(Int_t other = 1; other < rule->GetTarget()->GetEntriesFast(); ++other) {
4954 objstr = (TObjString*)(rule->GetTarget()->At(other));
4955 if (objstr) {
4956 newName = objstr->String();
4957 if ( TDataMember* dm = fClass->GetDataMember( newName ) ) {
4960 TStreamerInfo::kArtificial, dm->GetTypeName());
4961 toAdd.push_back(newel);
4962 }
4963 }
4964 }
4965 } // For each target of the rule
4966 }
4967 // Now find where with need to add them
4968 TIter s_iter(rule->GetSource());
4969 Int_t loc = -1;
4970 while( TObjString *s = (TObjString*)s_iter() ) {
4971 for(Int_t i = fElements->GetLast(); i >= 0 && (i+1) >= loc; --i) {
4972 if (s->String() == fElements->UncheckedAt(i)->GetName()) {
4973 if (loc == -1 || (i+1)>loc) {
4974 loc = i+1;
4975 }
4976 }
4977 }
4978 }
4979 if (loc == -1) {
4980 // Verify if the last one is not 'skipped'.
4981 for(Int_t i = fElements->GetLast(); i >= 0 && (i+1) >= loc; --i) {
4984 break;
4985 }
4986 loc = i;
4987 }
4988 }
4989 if (loc == -1) {
4990 for(auto &el : toAdd) {
4991 fElements->Add(el);
4992 }
4993 } else {
4995 }
4996 } // None of the target of the rule are on file.
4997}
4998
4999////////////////////////////////////////////////////////////////////////////////
5000/// List the TStreamerElement list and also the precomputed tables
5001/// if option contains the string "incOrig", also prints the original
5002/// (non-optimized elements in the list of compiled elements.
5003
5005{
5006 if (fClass && (fName != fClass->GetName())) {
5007 if (fClass->IsVersioned()) {
5008 Printf("\nStreamerInfo for conversion to %s from: %s, version=%d, checksum=0x%x",fClass->GetName(),GetName(),fClassVersion,GetCheckSum());
5009 } else {
5010 Printf("\nStreamerInfo for conversion to %s from: %s, checksum=0x%x",fClass->GetName(),GetName(),GetCheckSum());
5011 }
5012 } else {
5013 if (!fClass || fClass->IsVersioned()) {
5014 Printf("\nStreamerInfo for class: %s, version=%d, checksum=0x%x",GetName(),fClassVersion,GetCheckSum());
5015 } else {
5016 Printf("\nStreamerInfo for class: %s, checksum=0x%x",GetName(),GetCheckSum());
5017 }
5018 }
5019
5020 if (fElements) {
5021 TIter next(fElements);
5022 TObject *obj;
5023 while ((obj = next()))
5024 obj->ls(option);
5025 }
5026 Bool_t noaddr = option && (strstr(option,"noaddr") != nullptr);
5027
5028 if (strstr(option,"full") != 0) {
5029 for (Int_t i=0; i < fNfulldata; ++i) {
5032 element->GetSequenceType(sequenceType);
5033 // by definition of the loop (i+1) <= fNdata
5034 if (sequenceType.Length()) {
5035 sequenceType.Prepend(" [");
5036 sequenceType += "]";
5037 }
5038 Printf(" i=%2d, %-15s type=%3d, offset=%3d, len=%d, method=%ld%s",
5039 i,element->GetName(),fCompFull[i]->fType,fCompFull[i]->fOffset,fCompFull[i]->fLength, (noaddr ? 0 : fCompFull[i]->fMethod),
5040 sequenceType.Data());
5041 }
5042
5043 } else {
5044 Bool_t wantOrig = strstr(option,"incOrig") != 0;
5046 for (Int_t i=0,j=0;i < fNdata;++i,++j) {
5049 element->GetSequenceType(sequenceType);
5050 // by definition of the loop (i+1) <= fNdata
5052 if (optimized) {
5053 // This was optimized.
5054 if (sequenceType.Length() != 0) {
5055 sequenceType += ',';
5056 }
5057 sequenceType += "optimized";
5058 }
5059 if (sequenceType.Length()) {
5060 sequenceType.Prepend(" [");
5061 sequenceType += "]";
5062 }
5063 Printf(" i=%2d, %-15s type=%3d, offset=%3d, len=%d, method=%ld%s",
5064 i,element->GetName(),fCompOpt[i]->fType,fCompOpt[i]->fOffset,fCompOpt[i]->fLength, (noaddr ? 0 : fCompOpt[i]->fMethod),
5065 sequenceType.Data());
5066 if (optimized && wantOrig) {
5067 Bool_t done;
5068 do {
5069 element = (TStreamerElement*)fCompFull[j]->fElem;
5070 element->GetSequenceType(sequenceType);
5071 if (sequenceType.Length()) {
5072 sequenceType.Prepend(" [");
5073 sequenceType += "]";
5074 }
5075 Printf(" j=%2d, %-15s type=%3d, offset=%3d, len=%d, method=%ld%s",
5077 sequenceType.Data());
5078 ++j;
5079 done = j >= fNfulldata || ( (i+1 < fNdata) && fCompOpt[i+1]->fElem == fCompFull[j+1]->fElem );
5080 } while (!done);
5081
5082 }
5083 }
5084 }
5085}
5086
5087////////////////////////////////////////////////////////////////////////////////
5088/// An emulated object is created at address obj, if obj is null we
5089/// allocate memory for the object.
5090
5091void* TStreamerInfo::New(void *obj)
5092{
5093 //???FIX ME: What about varying length array elements?
5094
5095 char* p = (char*) obj;
5096
5097 TIter next(fElements);
5098
5099 if (!p) {
5100 // Allocate and initialize the memory block. Ensure the returned
5101 // storage is aligned to the class alignment requirement.
5102 auto align = fClass->GetClassAlignment();
5103 // Use aligned new (C++17). This will return memory aligned to
5104 // 'align' and can be freed with the matching delete[].
5105 assert(ROOT::Internal::IsValidAlignment(align)); // align must be a power of 2
5106 p = static_cast<char *>(::operator new[](fSize, std::align_val_t(align)));
5107 memset(p, 0, fSize);
5108 }
5109
5110 next.Reset();
5112
5113 for (; element; element = (TStreamerElement*) next()) {
5114
5115 // Skip elements which have not been allocated memory.
5116 if (element->GetOffset() == kMissing) {
5117 continue;
5118 }
5119
5120 // Skip elements for which we do not have any class
5121 // information. FIXME: Document how this could happen.
5122 TClass *cle = element->GetNewClass();
5123 if (!cle)
5124 cle = element->GetClassPointer();
5125 if (!cle)
5126 continue;
5127
5128 char* eaddr = p + element->GetOffset();
5129 Int_t etype = element->GetNewType();
5130 if (etype == TStreamerInfo::kNoType)
5131 etype = element->GetType();
5132
5133 //cle->GetStreamerInfo(); //necessary in case "->" is not specified
5134
5135 switch (etype) {
5136
5137 case kAnyP:
5138 case kObjectP:
5139 case kSTLp:
5140 {
5141 // Initialize array of pointers with null pointers.
5142 char** r = (char**) eaddr;
5143 Int_t len = element->GetArrayLength();
5144 for (Int_t i = 0; i < len; ++i) {
5145 r[i] = 0;
5146 }
5147 }
5148 break;
5149
5150 case kObjectp:
5151 case kAnyp:
5152 {
5153 // If the option "->" is given in the data member comment field
5154 // it is assumed that the object exists before reading data in,
5155 // so we create an object.
5156 if (cle != TClonesArray::Class()) {
5157 void** r = (void**) eaddr;
5158 *r = cle->New();
5159 } else {
5160 // In the case of a TClonesArray, the class name of
5161 // the contained objects must be specified in the
5162 // data member comment in this format:
5163 // TClonesArray* myVar; //->(className)
5164 const char* title = element->GetTitle();
5165 const char* bracket1 = strrchr(title, '(');
5166 const char* bracket2 = strrchr(title, ')');
5167 if (bracket1 && bracket2 && (bracket2 != (bracket1 + 1))) {
5168 Int_t len = bracket2 - (bracket1 + 1);
5169 char* clonesClass = new char[len+1];
5170 clonesClass[0] = '\0';
5172 void** r = (void**) eaddr;
5173 *r = (void*) new TClonesArray(clonesClass);
5174 delete[] clonesClass;
5175 } else {
5176 //Warning("New", "No class name found for TClonesArray initializer in data member comment (expected \"//->(className)\"");
5177 void** r = (void**) eaddr;
5178 *r = (void*) new TClonesArray();
5179 }
5180 }
5181 }
5182 break;
5183
5184 case kBase:
5185 {
5186 if (cle->Property() & kIsAbstract) {
5187 TVirtualStreamerInfo *einfo = cle->GetStreamerInfoAbstractEmulated();
5188 if (einfo) einfo->New(eaddr);
5189 } else {
5190 cle->New(eaddr);
5191 }
5192 break;
5193 }
5194 case kObject:
5195 case kAny:
5196 case kTObject:
5197 case kTString:
5198 case kTNamed:
5199 {
5200 cle->New(eaddr);
5201 }
5202 break;
5203
5204 case kSTL:
5205 {
5206 if (strcmp(element->GetName(),"This")==0 &&
5207 !cle->GetCollectionProxy()) {
5208 // missing information, avoid infinite loop
5209 // by doing nothing ....
5210 } else {
5211 if (cle->GetCollectionProxy())
5212 cle->GetCollectionProxy()->New(eaddr);
5213 else
5214 cle->New(eaddr);
5215 }
5216 }
5217 break;
5218
5219 case kObject + kOffsetL:
5220 case kAny + kOffsetL:
5221 case kTObject + kOffsetL:
5222 case kTString + kOffsetL:
5223 case kTNamed + kOffsetL:
5224 case kSTL + kOffsetL:
5225 {
5226 Int_t size = cle->Size();
5227 char* r = eaddr;
5228 Int_t len = element->GetArrayLength();
5229 for (Int_t i = 0; i < len; ++i, r += size) {
5230 cle->New(r);
5231 }
5232 }
5233 break;
5234
5235 } // switch etype
5236 } // for TIter next(fElements)
5237
5238 for(int nbase = 0; nbase < fNVirtualInfoLoc; ++nbase) {
5239 *(TStreamerInfo**)(p + fVirtualInfoLoc[nbase]) = this;
5240 }
5241 return p;
5242}
5243
5244////////////////////////////////////////////////////////////////////////////////
5245/// An array of emulated objects is created at address ary, if ary is null,
5246/// we allocate memory for the array.
5247
5249{
5250 if (fClass == 0) {
5251 Error("NewArray", "TClass pointer is null!");
5252 return 0;
5253 }
5254
5255 Int_t size = fClass->Size();
5256
5257 char* p = (char*) ary;
5258
5259 // Determine the alignment requirement for the class.
5260 const ArrayCookieLayout layout(fClass);
5261
5262 if (!p) {
5263
5264 Long_t len = nElements * size + layout.headerSize;
5265
5266 // Allocate and initialize the memory block. Request alignment so
5267 // that the raw block starts on an 'align'-boundary; combined with
5268 // the rounded-up header this guarantees dataBegin is also aligned.
5269 p = static_cast<char *>(::operator new[](len, std::align_val_t(layout.align)));
5270 memset(p, 0, len);
5271 }
5272
5273 Long_t* r = (Long_t*)(p + layout.headerSize - layout.cookieSize);
5274 r[0] = size;
5275 r[1] = nElements;
5276 char *dataBegin = p + layout.headerSize;
5277
5278 // Do a placement new for each element.
5279 char *q = dataBegin;
5280 for (Long_t cnt = 0; cnt < nElements; ++cnt) {
5281 New(q);
5282 q += size;
5283 } // for nElements
5284
5285 return dataBegin;
5286}
5287
5288
5289#define DeleteBasicPointer(addr,element,name) \
5290 { \
5291 name **f = (name**)(addr); \
5292 int n = element->GetArrayLength() ? element->GetArrayLength() : 1;\
5293 for(int j=0;j<n;j++) { \
5294 delete [] f[j]; \
5295 f[j] = 0; \
5296 } \
5297 }
5298
5299////////////////////////////////////////////////////////////////////////////////
5300/// Internal part of the destructor.
5301/// Destruct each of the datamembers in the same order
5302/// as the implicit destructor would.
5303
5305{
5306 R__ASSERT(obj != 0);
5307
5308 char *p = (char*)obj;
5309
5311 //for (; ele; ele = (TStreamerElement*) next())
5312 for (Int_t elenum = nelements - 1; elenum >= 0; --elenum) {
5314 if (ele->GetOffset() == kMissing) continue;
5315 char* eaddr = p + ele->GetOffset();
5316
5317 Int_t etype = ele->GetNewType(); // in memory type
5318 if (etype == TStreamerInfo::kNoType)
5319 etype = ele->GetType();
5320
5321 switch(etype) {
5338 }
5339
5340 TClass *cle = ele->GetNewClass(); // in memory type
5341 if (!cle)
5342 cle = ele->GetClassPointer();
5343 if (!cle)
5344 continue;
5345
5346 if (etype == kObjectp || etype == kAnyp) {
5347 // Destroy an array of pre-allocated objects.
5348 Int_t len = ele->GetArrayLength();
5349 if (!len) {
5350 len = 1;
5351 }
5352 void** r = (void**) eaddr;
5353 for (Int_t j = len - 1; j >= 0; --j) {
5354 if (r[j]) {
5355 cle->Destructor(r[j]);
5356 r[j] = 0;
5357 }
5358 }
5359 }
5360
5361 if ((etype == kObjectP || etype == kAnyP || etype == kSTLp) && !ele->TestBit(TStreamerElement::kDoNotDelete)) {
5362 // Destroy an array of pointers to not-pre-allocated objects.
5363 Int_t len = ele->GetArrayLength();
5364 if (!len) {
5365 len = 1;
5366 }
5367 void** r = (void**) eaddr;
5368 for (Int_t j = len - 1; j >= 0; --j) {
5369 if (r[j]) {
5370 cle->Destructor(r[j]);
5371 r[j] = 0;
5372 }
5373 }
5374 }
5375
5376 if (etype == kBase) {
5377 if (cle->Property() & kIsAbstract) {
5378 TVirtualStreamerInfo *einfo = cle->GetStreamerInfoAbstractEmulated();
5379 if (einfo) einfo->Destructor(eaddr, kTRUE);
5380 } else {
5381 cle->Destructor(eaddr, kTRUE);
5382 }
5383 }
5384
5385 if (etype == kObject || etype == kAny ||
5386 etype == kTObject || etype == kTString || etype == kTNamed) {
5387 // A data member is destroyed, but not deleted.
5388 cle->Destructor(eaddr, kTRUE);
5389 }
5390
5391 if (etype == kSTL) {
5392 // A data member is destroyed, but not deleted.
5393 TVirtualCollectionProxy *pr = cle->GetCollectionProxy();
5394 if (!pr) {
5395 if (strcmp(ele->GetName(),"This")==0) {
5396 // missing information, avoid infinite loop
5397 // by doing nothing ....
5398 } else {
5399 cle->Destructor(eaddr, kTRUE);
5400 }
5401 } else {
5402 if (ele->TestBit(TStreamerElement::kDoNotDelete)) {
5403 TVirtualCollectionProxy::TPushPop env(cle->GetCollectionProxy(), eaddr); // used for both this 'clear' and the 'clear' inside destructor.
5404 cle->GetCollectionProxy()->Clear(); // empty the collection without deleting the pointer
5405 pr->Destructor(eaddr, kTRUE);
5406 } else {
5407 pr->Destructor(eaddr, kTRUE);
5408 }
5409 }
5410 }
5411
5412 if (etype == kObject + kOffsetL || etype == kAny + kOffsetL ||
5413 etype == kTObject + kOffsetL || etype == kTString + kOffsetL ||
5414 etype == kTNamed + kOffsetL || etype == kSTL + kOffsetL) {
5415 // For a data member which is an array of objects, we
5416 // destroy the objects, but do not delete them.
5417 Int_t len = ele->GetArrayLength();
5418 Int_t size = cle->Size();
5419 char* r = eaddr + (size * (len - 1));
5420 for (Int_t j = len - 1; j >= 0; --j, r -= size) {
5421 cle->Destructor(r, kTRUE);
5422 }
5423 }
5424 } // iter over elements
5425
5426 if (!dtorOnly) {
5427 // Note: We rely on fClass->GetClassAlignment() being the same than we had
5428 // on construction time.
5429 // However it technically can change but there is no much we can sensibly do to detect it. eg. "allocate object,
5430 // unload library, reload library, destruct object" (but in this case the 'unload' library is meant to/should also
5431 // destruct the object (unload transaction) but this is not always possible) or "allocate emulated object, load
5432 // library, destruct object".
5434 ::operator delete[](p, std::align_val_t(fClass->GetClassAlignment()));
5435 }
5436}
5437
5438////////////////////////////////////////////////////////////////////////////////
5439/// Emulated destructor for this class.
5440///
5441/// An emulated object is destroyed at address p.
5442/// Destruct each of the datamembers in the same order
5443/// as the implicit destructor would.
5444
5446{
5447 // Do nothing if passed a null pointer.
5448 if (obj == 0) return;
5449
5450 char* p = (char*) obj;
5451
5452 if (!dtorOnly && fNVirtualInfoLoc) {
5453 // !dtorOnly is used to filter out the case where this is called for
5454 // a base class or embedded object of the outer most class.
5455 TStreamerInfo *allocator = *(TStreamerInfo**)(p + fVirtualInfoLoc[0]);
5456 if (allocator != this) {
5457
5459
5460 p -= baseoffset;
5461 allocator->DestructorImpl(p, kFALSE);
5462 return;
5463 }
5464 }
5466}
5467
5468////////////////////////////////////////////////////////////////////////////////
5469/// Destroy an array of emulated objects, with optional delete.
5470
5472{
5473 // Do nothing if passed a null pointer.
5474 if (ary == 0) return;
5475
5476 //???FIX ME: What about varying length arrays?
5477
5478 // Recover the cookie layout: the two Long_t values sit in the header
5479 // block immediately before dataBegin, with the same alignment-based
5480 // headerSize that NewArray used.
5481 const ArrayCookieLayout layout(fClass);
5482
5483 Long_t *r = (Long_t *)((char *)ary - layout.cookieSize);
5484 Long_t arrayLen = r[1];
5485 Long_t size = r[0];
5486 char *memBegin = (char *)ary - layout.headerSize;
5487
5488 char* p = ((char*) ary) + ((arrayLen - 1) * size);
5489 for (Long_t cnt = 0; cnt < arrayLen; ++cnt, p -= size) {
5490 // Destroy each element, but do not delete it.
5491 Destructor(p, kTRUE);
5492 } // for arrayItemSize
5493
5494 if (!dtorOnly) {
5495 ::operator delete[](memBegin, std::align_val_t(layout.align));
5496 }
5497}
5498
5499////////////////////////////////////////////////////////////////////////////////
5500/// print value of element i in object at pointer
5501/// The function may be called in two ways:
5502/// -method1 len < 0
5503/// i is assumed to be the TStreamerElement number i in StreamerInfo
5504/// -method2 len >= 0
5505/// i is the type
5506/// address of variable is directly pointer.
5507/// len is the number of elements to be printed starting at pointer.
5508
5509void TStreamerInfo::PrintValue(const char *name, char *pointer, Int_t i, Int_t len, Int_t lenmax) const
5510{
5511 char *ladd;
5513 printf(" %-15s = ",name);
5514
5516 Int_t *count = 0;
5517 if (len >= 0) {
5518 ladd = pointer;
5519 atype = i;
5520 aleng = len;
5521 } else {
5522 if (i < 0) {
5523 if (pointer==0) {
5524 printf("nullptr\n");
5525 } else {
5526 const static TClassRef stringClass("string");
5527 if (fClass == stringClass) {
5528 std::string *st = (std::string*)(pointer);
5529 printf("%s\n",st->c_str());
5530 } else if (fClass == TString::Class()) {
5531 TString *st = (TString*)(pointer);
5532 printf("%s\n",st->Data());
5533 } else {
5534 printf("(%s*)0x%zx\n",GetName(),(size_t)pointer);
5535 }
5536 }
5537 return;
5538 }
5539 ladd = pointer + fCompFull[i]->fOffset;
5540 atype = fCompFull[i]->fNewType;
5541 aleng = fCompFull[i]->fLength;
5542 aElement = (TStreamerElement*)fCompFull[i]->fElem;
5543 count = (Int_t*)(pointer+fCompFull[i]->fMethod);
5544 }
5545 if (aleng > lenmax) aleng = lenmax;
5546
5548 printf("\n");
5549}
5550
5551////////////////////////////////////////////////////////////////////////////////
5552/// Print value of element i in a TClonesArray.
5553
5555{
5556 if (!clones) {printf(" %-15s = \n",name); return;}
5557 printf(" %-15s = ",name);
5558 Int_t nc = clones->GetEntriesFast();
5559 if (nc > lenmax) nc = lenmax;
5560
5563 int aleng = fCompFull[i]->fLength;
5564 if (aleng > lenmax) aleng = lenmax;
5565
5566 for (Int_t k=0;k < nc;k++) {
5567 char *pointer = (char*)clones->UncheckedAt(k);
5568 char *ladd = pointer+offset;
5569 Int_t *count = (Int_t*)(pointer+fCompFull[i]->fMethod);
5570 PrintValueAux(ladd,fCompFull[i]->fNewType,aElement, aleng, count);
5571 if (k < nc-1) printf(", ");
5572 }
5573 printf("\n");
5574}
5575
5576////////////////////////////////////////////////////////////////////////////////
5577/// Print value of element i in an STL container.
5578
5580{
5581 if (!cont) {printf(" %-15s = \n",name); return;}
5582 printf(" %-15s = ",name);
5583 Int_t nc = cont->Size();
5584 if (nc > lenmax) nc = lenmax;
5585
5588 int aleng = fCompFull[i]->fLength;
5589 if (aleng > lenmax) aleng = lenmax;
5590
5591 for (Int_t k=0;k < nc;k++) {
5592 char *pointer = (char*)cont->At(k);
5593 char *ladd = pointer+offset;
5594 Int_t *count = (Int_t*)(pointer+fCompFull[i]->fMethod);
5595 PrintValueAux(ladd,fCompFull[i]->fNewType,aElement, aleng, count);
5596 if (k < nc-1) printf(", ");
5597 }
5598 printf("\n");
5599}
5600
5601////////////////////////////////////////////////////////////////////////////////
5602/// Replace the TClass this streamerInfo is pointing to (belongs to)
5603
5605{
5606 if (newcl) {
5607 // This is mostly (but not only) for the artificial "This" streamerElement for an stl collection.
5609 }
5610 fClass = newcl;
5611}
5612
5613////////////////////////////////////////////////////////////////////////////////
5614/// Stream an object of class TStreamerInfo.
5615
5617{
5618 UInt_t R__s, R__c;
5619 if (R__b.IsReading()) {
5620 Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
5621 fOldVersion = R__v;
5622 if (R__v > 1) {
5623 //R__b.ReadClassBuffer(TStreamerInfo::Class(), this, R__v, R__s, R__c);
5624 R__b.ClassBegin(TStreamerInfo::Class(), R__v);
5625 R__b.ClassMember("TNamed");
5628 R__b.ClassMember("fCheckSum","UInt_t");
5629 R__b >> fCheckSum;
5630 R__b.ClassMember("fClassVersion","Int_t");
5633 R__b.ClassMember("fElements","TObjArray*");
5634 R__b >> fElements;
5635 R__b.ClassEnd(TStreamerInfo::Class());
5636 R__b.SetBufferOffset(R__s+R__c+sizeof(UInt_t));
5640
5641 if (R__b.GetParent() && R__b.GetVersionOwner() < 50000)
5642 {
5643 // In some older files, the type of the TStreamerElement was not
5644 // as we (now) expect.
5647 for (Int_t i = 0; i < nobjects; i++) {
5649 TStreamerElement *rel = 0;
5650 if ( el->IsA() == basic ) {
5651 switch (el->GetType()) {
5652 default: break; /* nothing */
5653 case TStreamerInfo::kObject: /*61*/
5654 rel = new TStreamerObject(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5655 break;
5656 case TStreamerInfo::kAny: /*62*/
5657 rel = new TStreamerObjectAny(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5658 break;
5659 case TStreamerInfo::kObjectp: /* 63 */
5660 rel = new TStreamerObjectPointer(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5661 break;
5662 case TStreamerInfo::kObjectP: /* 64 */
5663 rel = new TStreamerObjectPointer(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5664 break;
5665 case TStreamerInfo::kTString: /* 65 */
5666 rel = new TStreamerObject(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5667 break;
5668 }
5669 if (rel) {
5670 (*fElements)[i] = rel;
5671 delete el;
5672 }
5673 }
5674 }
5675 }
5676 return;
5677 }
5678 //====process old versions before automatic schema evolution
5681 R__b >> fCheckSum;
5684 R__b >> fElements;
5685 R__b.CheckByteCount(R__s, R__c, TStreamerInfo::IsA());
5686 } else {
5687 R__c = R__b.WriteVersion(TStreamerInfo::IsA(), kTRUE);
5688 R__b.ClassBegin(TStreamerInfo::Class());
5689 R__b.ClassMember("TNamed");
5691 R__b.ClassMember("fCheckSum","UInt_t");
5692 R__b << fCheckSum;
5693 R__b.ClassMember("fClassVersion","Int_t");
5695
5696 //------------------------------------------------------------------------
5697 // Stream only non-artificial streamer elements
5698 //////////////////////////////////////////////////////////////////////////
5699
5700 R__b.ClassMember("fElements","TObjArray*");
5701 {
5702 TObjArray elements(fElements->GetEntriesFast());
5705 for (Int_t i = 0; i < nobjects; i++) {
5707 if (el != 0 && (el->IsA() == TStreamerArtificial::Class() || el->TestBit(TStreamerElement::kRepeat))) {
5708 // skip
5709 } else if (el != 0 && (el->TestBit(TStreamerElement::kCache) && !el->TestBit(TStreamerElement::kWrite))) {
5710 // skip
5711 } else if (el != 0) {
5712 elements.AddLast(el);
5713 }
5714 }
5715 R__b.WriteObjectAny(&elements, TObjArray::Class(), kFALSE);
5716 }
5717 R__b.ClassEnd(TStreamerInfo::Class());
5718 R__b.SetByteCount(R__c, kTRUE);
5719 }
5720}
5721
5722////////////////////////////////////////////////////////////////////////////////
5723/// Mark the classindex of the current file as using this TStreamerInfo.
5724/// This function is deprecated and its functionality is now done by
5725/// the overloads of TBuffer::TagStreamerInfo.
5726
5728{
5729 if (file) {
5730 // If the value of the atomic is kFALSE (equal to expected), change its value
5731 // to kTRUE and return true. Leave it as it is otherwise and return false.
5732 static std::atomic<Bool_t> onlyonce(kFALSE);
5734 if (onlyonce.compare_exchange_strong(expected,kTRUE)) {
5735 Warning("TagFile","This function is deprecated, use TBuffer::TagStreamerInfo instead");
5736 }
5737 TArrayC *cindex = file->GetClassIndex();
5738 Int_t nindex = cindex->GetSize();
5740 Error("TagFile","StreamerInfo: %s number: %d out of range[0,%d] in file: %s",
5741 GetName(),fNumber,nindex,file->GetName());
5742 return;
5743 }
5744 if (cindex->fArray[fNumber] == 0) {
5745 cindex->fArray[0] = 1;
5746 cindex->fArray[fNumber] = 1;
5747 }
5748 }
5749}
5750
5751////////////////////////////////////////////////////////////////////////////////
5752
5753#ifdef DOLOOP
5754#undef DOLOOP
5755#endif
5756#define DOLOOP for (k = 0, pointer = arr[0]; k < narr; pointer = arr[++k])
5757
5758namespace {
5759 static void PrintCR(int j,Int_t aleng, UInt_t ltype)
5760 {
5761 if (j == aleng-1) printf("\n");
5762 else {
5763 printf(", ");
5764 if (j%ltype == ltype-1) printf("\n ");
5765 }
5766 }
5767}
5768
5769////////////////////////////////////////////////////////////////////////////////
5770/// print value of element in object at pointer, type atype, leng aleng or *count
5771/// The function may be called in two ways:
5772/// -method1 len < 0
5773/// i is assumed to be the TStreamerElement number i in StreamerInfo
5774/// -method2 len >= 0
5775/// i is the type
5776/// address of variable is directly pointer.
5777/// len is the number of elements to be printed starting at pointer.
5778
5780{
5781 int j;
5782
5783 //assert(!((kOffsetP + kChar) <= atype && atype <= (kOffsetP + kBool) && count == 0));
5784 switch (atype) {
5785 // basic types
5786 case kBool: {Bool_t *val = (Bool_t* )ladd; printf("%d" ,*val); break;}
5787 case kChar: {Char_t *val = (Char_t* )ladd; printf("%d" ,*val); break;}
5788 case kShort: {Short_t *val = (Short_t* )ladd; printf("%d" ,*val); break;}
5789 case kInt: {Int_t *val = (Int_t* )ladd; printf("%d" ,*val); break;}
5790 case kLong: {Long_t *val = (Long_t* )ladd; printf("%ld",*val); break;}
5791 case kLong64: {Long64_t *val = (Long64_t* )ladd; printf("%lld",*val); break;}
5792 case kFloat: {Float_t *val = (Float_t* )ladd; printf("%f" ,*val); break;}
5793 case kFloat16: {Float_t *val = (Float_t* )ladd; printf("%f" ,*val); break;}
5794 case kDouble: {Double_t *val = (Double_t* )ladd; printf("%g" ,*val); break;}
5795 case kDouble32: {Double_t *val = (Double_t* )ladd; printf("%g" ,*val); break;}
5796 case kUChar: {UChar_t *val = (UChar_t* )ladd; printf("%u" ,*val); break;}
5797 case kUShort: {UShort_t *val = (UShort_t* )ladd; printf("%u" ,*val); break;}
5798 case kUInt: {UInt_t *val = (UInt_t* )ladd; printf("%u" ,*val); break;}
5799 case kULong: {ULong_t *val = (ULong_t* )ladd; printf("%lu",*val); break;}
5800 case kULong64: {ULong64_t *val = (ULong64_t*)ladd; printf("%llu",*val); break;}
5801 case kBits: {UInt_t *val = (UInt_t* )ladd; printf("%d" ,*val); break;}
5802
5803 // array of basic types array[8]
5804 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;}
5805 case kOffsetL + kChar: {Char_t *val = (Char_t* )ladd; for(j=0;j<aleng;j++) { printf("%c " ,val[j]); PrintCR(j,aleng,20); } break;}
5806 case kOffsetL + kShort: {Short_t *val = (Short_t* )ladd; for(j=0;j<aleng;j++) { printf("%d " ,val[j]); PrintCR(j,aleng,10); } break;}
5807 case kOffsetL + kInt: {Int_t *val = (Int_t* )ladd; for(j=0;j<aleng;j++) { printf("%d " ,val[j]); PrintCR(j,aleng,10); } break;}
5808 case kOffsetL + kLong: {Long_t *val = (Long_t* )ladd; for(j=0;j<aleng;j++) { printf("%ld ",val[j]); PrintCR(j,aleng, 5); } break;}
5809 case kOffsetL + kLong64: {Long64_t *val = (Long64_t* )ladd; for(j=0;j<aleng;j++) { printf("%lld ",val[j]);PrintCR(j,aleng, 5); } break;}
5810 case kOffsetL + kFloat: {Float_t *val = (Float_t* )ladd; for(j=0;j<aleng;j++) { printf("%f " ,val[j]); PrintCR(j,aleng, 5); } break;}
5811 case kOffsetL + kFloat16: {Float_t *val = (Float_t* )ladd; for(j=0;j<aleng;j++) { printf("%f " ,val[j]); PrintCR(j,aleng, 5); } break;}
5812 case kOffsetL + kDouble: {Double_t *val = (Double_t* )ladd; for(j=0;j<aleng;j++) { printf("%g " ,val[j]); PrintCR(j,aleng, 5); } break;}
5813 case kOffsetL + kDouble32:{Double_t *val = (Double_t* )ladd; for(j=0;j<aleng;j++) { printf("%g " ,val[j]); PrintCR(j,aleng, 5); } break;}
5814 case kOffsetL + kUChar: {UChar_t *val = (UChar_t* )ladd; for(j=0;j<aleng;j++) { printf("%u " ,val[j]); PrintCR(j,aleng,20); } break;}
5815 case kOffsetL + kUShort: {UShort_t *val = (UShort_t* )ladd; for(j=0;j<aleng;j++) { printf("%u " ,val[j]); PrintCR(j,aleng,10); } break;}
5816 case kOffsetL + kUInt: {UInt_t *val = (UInt_t* )ladd; for(j=0;j<aleng;j++) { printf("%u " ,val[j]); PrintCR(j,aleng, 5); } break;}
5817 case kOffsetL + kULong: {ULong_t *val = (ULong_t* )ladd; for(j=0;j<aleng;j++) { printf("%lu ",val[j]); PrintCR(j,aleng, 5); } break;}
5818 case kOffsetL + kULong64: {ULong64_t *val = (ULong64_t*)ladd; for(j=0;j<aleng;j++) { printf("%llu ",val[j]);PrintCR(j,aleng, 5); } break;}
5819 case kOffsetL + kBits: {UInt_t *val = (UInt_t* )ladd; for(j=0;j<aleng;j++) { printf("%d " ,val[j]); PrintCR(j,aleng, 5); } break;}
5820
5821 // pointer to an array of basic types array[n]
5822 case kOffsetP + kBool: {Bool_t **val = (Bool_t** )ladd; for(j=0;j<*count;j++) { printf("%d " ,(*val)[j]); PrintCR(j,aleng,20); } break;}
5823 case kOffsetP + kChar: {Char_t **val = (Char_t** )ladd; for(j=0;j<*count;j++) { printf("%d " ,(*val)[j]); PrintCR(j,aleng,20); } break;}
5824 case kOffsetP + kShort: {Short_t **val = (Short_t** )ladd; for(j=0;j<*count;j++) { printf("%d " ,(*val)[j]); PrintCR(j,aleng,10); } break;}
5825 case kOffsetP + kInt: {Int_t **val = (Int_t** )ladd; for(j=0;j<*count;j++) { printf("%d " ,(*val)[j]); PrintCR(j,aleng,10); } break;}
5826 case kOffsetP + kLong: {Long_t **val = (Long_t** )ladd; for(j=0;j<*count;j++) { printf("%ld ",(*val)[j]); PrintCR(j,aleng, 5); } break;}
5827 case kOffsetP + kLong64: {Long64_t **val = (Long64_t**)ladd; for(j=0;j<*count;j++) { printf("%lld ",(*val)[j]); PrintCR(j,aleng, 5); } break;}
5828 case kOffsetP + kFloat: {Float_t **val = (Float_t** )ladd; for(j=0;j<*count;j++) { printf("%f " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5829 case kOffsetP + kFloat16: {Float_t **val = (Float_t** )ladd; for(j=0;j<*count;j++) { printf("%f " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5830 case kOffsetP + kDouble: {Double_t **val = (Double_t**)ladd; for(j=0;j<*count;j++) { printf("%g " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5831 case kOffsetP + kDouble32:{Double_t **val = (Double_t**)ladd; for(j=0;j<*count;j++) { printf("%g " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5832 case kOffsetP + kUChar: {UChar_t **val = (UChar_t** )ladd; for(j=0;j<*count;j++) { printf("%u " ,(*val)[j]); PrintCR(j,aleng,20); } break;}
5833 case kOffsetP + kUShort: {UShort_t **val = (UShort_t**)ladd; for(j=0;j<*count;j++) { printf("%u " ,(*val)[j]); PrintCR(j,aleng,10); } break;}
5834 case kOffsetP + kUInt: {UInt_t **val = (UInt_t** )ladd; for(j=0;j<*count;j++) { printf("%u " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5835 case kOffsetP + kULong: {ULong_t **val = (ULong_t** )ladd; for(j=0;j<*count;j++) { printf("%lu ",(*val)[j]); PrintCR(j,aleng, 5); } break;}
5836 case kOffsetP + kULong64: {ULong64_t**val = (ULong64_t**)ladd; for(j=0;j<*count;j++){ printf("%llu ",(*val)[j]); PrintCR(j,aleng, 5); } break;}
5837
5838 // array counter //[n]
5839 case kCounter: {Int_t *val = (Int_t*)ladd; printf("%d",*val); break;}
5840 // char *
5841 case kCharStar:{
5842 char **val = (char**)ladd;
5843 if (*val) printf("%s",*val);
5844 break;
5845 }
5846 // Class * derived from TObject with comment field //->
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 kObjectP: {
5856 TObject **obj = (TObject**)(ladd);
5858 printf("(%s*)%zx",el ? el->GetClass()->GetName() : "unknown_type",(size_t)(*obj));
5859 break;
5860 }
5861
5862 // Class derived from TObject
5863 case kObject: {
5864 TObject *obj = (TObject*)(ladd);
5865 printf("%s",obj->GetName());
5866 break;
5867 }
5868
5869 // Special case for TString, TObject, TNamed
5870 case kTString: {
5871 TString *st = (TString*)(ladd);
5872 printf("%s",st->Data());
5873 break;
5874 }
5875 case kTObject: {
5876 TObject *obj = (TObject*)(ladd);
5877 printf("%s",obj->GetName());
5878 break;
5879 }
5880 case kTNamed: {
5881 TNamed *named = (TNamed*) (ladd);
5882 printf("%s/%s",named->GetName(),named->GetTitle());
5883 break;
5884 }
5885
5886 // Class * not derived from TObject with comment field //->
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
5894 // Class* not derived from TObject
5895 case kAnyP: {
5896 TObject **obj = (TObject**)(ladd);
5898 printf("(%s*)0x%zx",el ? el->GetClass()->GetName() : "unknown_type",(size_t)(*obj));
5899 break;
5900 }
5901 // Any Class not derived from TObject
5902 case kOffsetL + kObjectp:
5903 case kOffsetL + kObjectP:
5904 case kAny: {
5905 printf("printing kAny case (%d)",atype);
5906// if (aElement) {
5907// TMemberStreamer *pstreamer = aElement->GetStreamer();
5908// if (pstreamer == 0) {
5909// //printf("ERROR, Streamer is null\n");
5910// //aElement->ls();
5911// break;
5912// }
5913// //(*pstreamer)(b,ladd,0);
5914// }
5915 break;
5916 }
5917 // Base Class
5918 case kBase: {
5919 printf("printing kBase case (%d)",atype);
5920 //aElement->ReadBuffer(b,pointer);
5921 break;
5922 }
5923
5924 case kOffsetL + kObject:
5925 case kOffsetL + kTString:
5926 case kOffsetL + kTObject:
5927 case kOffsetL + kTNamed:
5928 case kStreamer: {
5929 printf("printing kStreamer case (%d)",atype);
5930// TMemberStreamer *pstreamer = aElement->GetStreamer();
5931// if (pstreamer == 0) {
5932// //printf("ERROR, Streamer is null\n");
5933// //aElement->ls();
5934// break;
5935// }
5936// //UInt_t start,count;
5937// //b.ReadVersion(&start, &count);
5938// //(*pstreamer)(b,ladd,0);
5939// //b.CheckByteCount(start,count,IsA());
5940 break;
5941 }
5942
5943 case kStreamLoop: {
5944 printf("printing kStreamLoop case (%d)",atype);
5945// TMemberStreamer *pstreamer = aElement->GetStreamer();
5946// if (pstreamer == 0) {
5947// //printf("ERROR, Streamer is null\n");
5948// //aElement->ls();
5949// break;
5950// }
5951 //Int_t *counter = (Int_t*)(count);
5952 //UInt_t start,count;
5953 ///b.ReadVersion(&start, &count);
5954 //(*pstreamer)(b,ladd,*counter);
5955 //b.CheckByteCount(start,count,IsA());
5956 break;
5957 }
5958 case kSTL: {
5959 if (aElement) {
5960 static TClassRef stringClass("string");
5961 if (ladd && aElement->GetClass() == stringClass) {
5962 std::string *st = (std::string*)(ladd);
5963 printf("%s",st->c_str());
5964 } else {
5965 printf("(%s*)0x%zx",aElement->GetClass()->GetName(),(size_t)(ladd));
5966 }
5967 } else {
5968 printf("(unknown_type*)0x%zx",(size_t)(ladd));
5969 }
5970 break;
5971 }
5972 }
5973}
5974
5975////////////////////////////////////////////////////////////////////////////////
5976///function called by the TClass constructor when replacing an emulated class
5977///by the real class
5978
5980{
5983 while ((element = (TStreamerElement*)nextElement())) {
5984 element->Update(oldcl,newcl);
5985 }
5986 for (Int_t i=0;i < fNslots;i++) {
5987 fComp[i].Update(oldcl,newcl);
5988 }
5989}
5990
5991////////////////////////////////////////////////////////////////////////////////
5992/// Update the TClass pointer cached in this object.
5993
5995{
5996 if (fType != -1) {
5997 if (fClass == oldcl || strcmp(fClassName, newcl->GetName()) == 0)
5998 fClass = newcl;
5999 else if (fClass == 0 && TClassTable::GetDict(fClassName))
6001 }
6002}
6003
6004////////////////////////////////////////////////////////////////////////////////
6005/// Generate emulated collection proxy for a given class.
6006
6012
6013////////////////////////////////////////////////////////////////////////////////
6014/// Generate emulated class streamer for a given collection class.
6015
6021
6022////////////////////////////////////////////////////////////////////////////////
6023/// Generate proxy from static functions.
6024
6026TStreamerInfo::GenExplicitProxy( const ::ROOT::TCollectionProxyInfo &info, TClass *cl )
6027{
6029}
6030
6031////////////////////////////////////////////////////////////////////////////////
6032/// Generate class streamer from static functions.
6033
6035TStreamerInfo::GenExplicitClassStreamer( const ::ROOT::TCollectionProxyInfo &info, TClass *cl )
6036{
6038}
6039
6040//
6041// Utility functions
6042//
6043static TStreamerElement *
6044R__CreateEmulatedElement(const char *dmName, const std::string &dmFull, Int_t offset, bool silent, bool needAlign)
6045{
6046 // Create a TStreamerElement for the type 'dmFull' and whose data member name is 'dmName'.
6047
6048 TString s1( TClassEdit::ShortType(dmFull.c_str(),0) );
6050 Bool_t dmIsPtr = (s1 != dmType);
6051 const char *dmTitle = "Emulation";
6052 // Over align the basic data types.
6053 size_t align = alignof(std::max_align_t);
6054 if (needAlign && offset % align != 0)
6055 offset = (Int_t)AlignUp((size_t)offset, align);
6056
6057 TDataType *dt = gROOT->GetType(dmType);
6058 if (dt && dt->GetType() > 0 ) { // found a basic type
6060 dtype = dt->GetType();
6061 dsize = dt->Size();
6062 // Use the precise alignment for the basic type if available.
6063 if (needAlign && dt->GetAlignOf()) {
6064 align = dt->GetAlignOf();
6065 if (offset % align != 0)
6066 offset = (Int_t)AlignUp((size_t)offset, align);
6067 }
6068 if (dmIsPtr && dtype != kCharStar) {
6069 if (!silent)
6070 Error("Pair Emulation Building","%s is not yet supported in pair emulation",
6071 dmFull.c_str());
6072 return 0;
6073 } else {
6075 el->SetSize(dsize);
6076 return el;
6077 }
6078 } else {
6079
6080 static const char *full_string_name = "basic_string<char,char_traits<char>,allocator<char> >";
6081 if (strcmp(dmType,"string") == 0 || strcmp(dmType,"std::string") == 0 || strcmp(dmType,full_string_name)==0 ) {
6083 }
6085 return new TStreamerSTL(dmName,dmTitle,offset,dmFull.c_str(),dmFull.c_str(),dmIsPtr);
6086 }
6088 if (!clm) {
6090 if (enumdesc) {
6091 auto dtype = enumdesc->GetUnderlyingType();
6092 auto el = new TStreamerBasicType(dmName, dmTitle, offset, dtype, dmFull.c_str());
6094 if (datatype)
6095 el->SetSize(datatype->Size());
6096 else
6097 el->SetSize(sizeof(int)); // Default size of enums.
6098 return el;
6099 }
6100 return nullptr;
6101 }
6102 if (clm->GetState() <= TClass::kForwardDeclared)
6103 return nullptr;
6104 // a pointer to a class
6105 if ( dmIsPtr ) {
6106 if (clm->IsTObject()) {
6108 } else {
6110 }
6111 }
6112 // a class
6113 assert(ROOT::Internal::IsValidAlignment(clm->GetClassAlignment()));
6114 align = std::max(align, clm->GetClassAlignment());
6115 if (needAlign && ((offset % align) != 0))
6116 offset = (Int_t)AlignUp((size_t)offset, align);
6117 if (clm->IsTObject()) {
6118 return new TStreamerObject(dmName,dmTitle,offset,dmFull.c_str());
6119 } else if(clm == TString::Class() && !dmIsPtr) {
6121 } else {
6122 return new TStreamerObjectAny(dmName,dmTitle,offset,dmFull.c_str());
6123 }
6124 }
6125}
6126
6127/// \brief Generate the TClass and TStreamerInfo for the requested pair.
6128/// This creates a TVirtualStreamerInfo for the pair and trigger the BuildCheck/Old to
6129/// provoke the creation of the corresponding TClass. This relies on the dictionary for
6130/// std::pair<const int, int> to already exist (or the interpreter information being available)
6131/// as it is used as a template.
6132/// \note The returned object is owned by the caller.
6134{
6135 // Generate a TStreamerInfo for a std::pair<fname,sname>
6136 // This TStreamerInfo is then used as if it was read from a file to generate
6137 // and emulated TClass.
6138
6140 const char *msg = "problematic";
6142 msg = "the same";
6143 else if (hint_pair_offset > hint_pair_size) {
6144 if (hint_pair_size == 0)
6145 msg = "not specified";
6146 else
6147 msg = "smaller";
6148 }
6149 Error("GenerateInfoForPair",
6150 "Called with inconsistent offset and size. For \"std::pair<%s,%s>\" the requested offset is %ld but the size is %s (%ld)",
6151 firstname.c_str(), secondname.c_str(), (long)hint_pair_offset, msg, (long)hint_pair_offset);
6152 return nullptr;
6153 }
6154 TStreamerInfo *i = (TStreamerInfo*)TClass::GetClass("pair<const int,int>")->GetStreamerInfo()->Clone();
6155 std::string pname = "pair<" + firstname + "," + secondname;
6156 pname += (pname[pname.length()-1]=='>') ? " >" : ">";
6157 i->SetName(pname.c_str());
6158 i->SetClass(nullptr);
6159 i->GetElements()->Delete();
6160 TStreamerElement *fel = R__CreateEmulatedElement("first", firstname, 0, silent, /*needAlign=*/false);
6161 Int_t size = 0;
6162 if (fel) {
6163 i->GetElements()->Add(fel);
6164 i->fAlignment = std::max(i->fAlignment, fel->GetAlignment());
6165 } else {
6166 delete i;
6167 return 0;
6168 }
6169 if (hint_pair_offset)
6171 TStreamerElement *second =
6172 R__CreateEmulatedElement("second", secondname, size, silent, /*needAlign=*/!hint_pair_offset);
6173 if (second) {
6174 i->GetElements()->Add(second);
6175 i->fAlignment = std::max(i->fAlignment, second->GetAlignment());
6176 } else {
6177 delete i;
6178 return 0;
6179 }
6181 // Hide the warning about the missing pair dictionary.
6183 i->BuildCheck(nullptr, kFALSE); // Skipping the loading part (it would leads to infinite recursion on this very routine)
6185 if (i->TestBit(kCanDelete)) {
6186 // The StreamerInfo was deemed to be a duplicated (most likely case is
6187 // that we have the interpreter information already loaded for the
6188 // pair), so we need to delete it and return the one we already have.
6189 auto cl = i->GetClass();
6190 delete i;
6191 return cl->GetStreamerInfo();
6192 }
6193
6194 // In the state emulated, BuildOld would recalculate the offset and undo the offset update.
6195 // Note: we should consider adding a new state just for this (the hints indicates that we are mapping a compiled class but
6196 // then we would have to investigate all use of the state with <= and >= condition to make sure they are still appropriate).
6197 if (hint_pair_size) {
6200 }
6201
6202 i->BuildOld();
6203
6204 if (hint_pair_size)
6206 return i;
6207}
6208
6210{
6211 const static int pairlen = std::char_traits<char>::length("pair<");
6212 if (pairclassname.compare(0, pairlen, "pair<") != 0) {
6213 if (!silent)
6214 Error("GenerateInfoForPair", "The class name passed is not a pair: %s", pairclassname.c_str());
6215 return nullptr;
6216 }
6217
6218 std::vector<std::string> inside;
6219 int nested = 0;
6220 int num = TClassEdit::GetSplit(pairclassname.c_str(), inside, nested);
6221 if (num != 4) {
6222 if (!silent)
6223 Error("GenerateInfoForPair", "Could not find the pair arguments in %s", pairclassname.c_str());
6224 return nullptr;
6225 }
6226
6227 return GenerateInfoForPair(inside[1], inside[2], silent, hint_pair_offset, hint_pair_size);
6228}
#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
bool Bool_t
Boolean (0=false, 1=true) (bool)
Definition RtypesCore.h:78
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:60
short Version_t
Class version identifier (short)
Definition RtypesCore.h:80
char Char_t
Character 1 byte (char)
Definition RtypesCore.h:52
unsigned long ULong_t
Unsigned long integer 4 bytes (unsigned long). Size depends on architecture.
Definition RtypesCore.h:70
long Long_t
Signed long integer 4 bytes (long). Size depends on architecture.
Definition RtypesCore.h:69
unsigned int UInt_t
Unsigned integer 4 bytes (unsigned int)
Definition RtypesCore.h:61
float Float_t
Float 4 bytes (float)
Definition RtypesCore.h:72
short Short_t
Signed Short integer 2 bytes (short)
Definition RtypesCore.h:54
constexpr Bool_t kFALSE
Definition RtypesCore.h:109
double Double_t
Double 8 bytes.
Definition RtypesCore.h:74
long double LongDouble_t
Long Double (not portable)
Definition RtypesCore.h:76
long long Long64_t
Portable signed long integer 8 bytes.
Definition RtypesCore.h:84
constexpr Bool_t kTRUE
Definition RtypesCore.h:108
const char Option_t
Option string (const char)
Definition RtypesCore.h:81
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
#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:130
constexpr Int_t kError
Definition TError.h:47
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition TError.cxx:208
Int_t gErrorIgnoreLevel
errors with level below this value will be ignored. Default is kUnset.
Definition TError.cxx:33
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t option
Option_t Option_t cindex
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char filename
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h offset
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize id
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t UChar_t len
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t attr
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t src
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
char name[80]
Definition TGX11.cxx:142
float * q
R__EXTERN TVirtualMutex * gInterpreterMutex
Int_t gDebug
Global variable setting the debug level. Set to 0 to disable, increase it in steps of 1 to increase t...
Definition TROOT.cxx:792
#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)
const Int_t kMaxLen
static void R__WriteConstructorBody(FILE *file, TIter &next)
#define DeleteBasicPointer(addr, element, name)
static constexpr int str_length(const char *str)
static 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:2585
R__EXTERN TSystem * gSystem
Definition TSystem.h:582
#define R__LOCKGUARD(mutex)
Int_t GetPointerLevel() const
Definition TSchemaRule.h:48
const char * GetUnderlyingTypeName() const
Definition TSchemaRule.h:50
const char * GetDimensions() const
Definition TSchemaRule.h:44
Array of chars or bytes (8 bits per element).
Definition TArrayC.h:27
Each class (see TClass) has a linked list of its base class(es).
Definition TBaseClass.h:33
Int_t GetDelta()
Get offset from "this" to part of base class.
ROOT::ESTLType IsSTLContainer()
Return which type (if any) of STL container the data member is.
TClass * GetClassPointer(Bool_t load=kTRUE)
Get pointer to the base class TClass.
const char * GetTitle() const override
Get base class description (comment).
Buffer base class used for serializing objects.
Definition TBuffer.h:43
TClassRef is used to implement a permanent reference to a TClass object.
Definition TClassRef.h:29
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:6679
Bool_t IsSyntheticPair() const
Definition TClass.h:538
TDataMember * GetDataMember(const char *datamember) const
Return pointer to datamember object with name "datamember".
Definition TClass.cxx:3506
EState GetState() const
Definition TClass.h:504
ROOT::ESTLType GetCollectionType() const
Return the 'type' of the STL the TClass is representing.
Definition TClass.cxx:2912
void RemoveStreamerInfo(Int_t slot)
Remove and delete the StreamerInfo in the given slot.
Definition TClass.cxx:7540
Bool_t HasDataMemberInfo() const
Definition TClass.h:420
void CopyCollectionProxy(const TVirtualCollectionProxy &)
Replaces the collection proxy for this class.
Definition TClass.cxx:2482
Bool_t fIsSyntheticPair
Indicates whether this class represents a pair and was not created from a dictionary nor interpreter ...
Definition TClass.h:258
void RegisterStreamerInfo(TVirtualStreamerInfo *info)
Register the StreamerInfo in the given slot, change the State of the TClass as appropriate.
Definition TClass.cxx:7516
TVirtualStreamerInfo * GetCurrentStreamerInfo()
Definition TClass.h:454
size_t GetClassAlignment() const
Return the alignment requirement (in bytes) for objects of this class.
Definition TClass.cxx:5844
void IgnoreTObjectStreamer(Bool_t ignore=kTRUE)
When the class kIgnoreTObjectStreamer bit is set, the automatically generated Streamer will not call ...
Definition TClass.cxx:4962
TClass * GetBaseClass(const char *classname)
Return pointer to the base class "classname".
Definition TClass.cxx:2667
Longptr_t GetDataMemberOffset(const char *membername) const
return offset for member name.
Definition TClass.cxx:3544
Bool_t MatchLegacyCheckSum(UInt_t checksum) const
Return true if the checksum passed as argument is one of the checksum value produced by the older che...
Definition TClass.cxx:6668
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:2043
TList * GetListOfDataMembers(Bool_t load=kTRUE)
Return list containing the TDataMembers of a class.
Definition TClass.cxx:3833
TList * GetListOfRealData() const
Definition TClass.h:468
Int_t Size() const
Return size of object of this class.
Definition TClass.cxx:5869
Bool_t CanIgnoreTObjectStreamer()
Definition TClass.h:406
const ROOT::Detail::TSchemaRuleSet * GetSchemaRules() const
Return the set of the schema rules if any.
Definition TClass.cxx:1939
TList * GetListOfBases()
Return list containing the TBaseClass(es) of a class.
Definition TClass.cxx:3699
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:6080
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition TClass.cxx:6106
Bool_t IsForeign() const
Return kTRUE is the class is Foreign (the class does not have a Streamer method).
Definition TClass.cxx:6115
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:4720
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:2817
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition TClass.cxx:2923
Int_t GetClassSize() const
Definition TClass.h:439
Long_t Property() const override
Returns the properties of the TClass as a bit field stored as a Long_t value.
Definition TClass.cxx:6254
@ 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:539
void SetClassSize(Int_t sizof)
Definition TClass.h:316
Version_t GetClassVersion() const
Definition TClass.h:434
TRealData * GetRealData(const char *name) const
Return pointer to TRealData element with name "name".
Definition TClass.cxx:3570
@ 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:2999
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
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.
Basic data type descriptor (datatype information is obtained from CINT).
Definition TDataType.h:44
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.
This class stores the date and time with a precision of one second in an unsigned 32 bit word (950130...
Definition TDatime.h:37
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:1391
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.
The TNamed class is the base class for all named ROOT classes.
Definition TNamed.h:29
TObject * Clone(const char *newname="") const override
Make a clone of an object using the Streamer facility.
Definition TNamed.cxx:73
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
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.
TObject * Last() const override
Return the object in the last filled slot. Returns 0 if no entries.
virtual void AddAtAndExpand(TObject *obj, Int_t idx)
Add object at position idx.
Int_t GetEntries() const override
Return the number of objects in array (i.e.
void Delete(Option_t *option="") override
Remove all objects from the array AND delete all heap based objects.
TObject * At(Int_t idx) const override
Definition TObjArray.h: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
Mother of all ROOT objects.
Definition TObject.h:42
friend class TClonesArray
Definition TObject.h:245
virtual const char * GetName() const
Returns name of object.
Definition TObject.cxx:461
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition TObject.h:204
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:1082
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:886
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1096
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition TObject.cxx:1124
virtual void ls(Option_t *option="") const
The ls function lists the contents of a class on stdout.
Definition TObject.cxx:597
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:1070
void Obsolete(const char *method, const char *asOfVers, const char *removedFromVers) const
Use this method to declare a method obsolete.
Definition TObject.cxx:1167
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
static TClass * Class()
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()
static TClass * Class()
Describe one element (data member) to be Streamed.
virtual TClass * GetClassPointer() const
Returns a pointer to the TClass of this element and updates fClassObject.
TClass * GetNewClass() const
Int_t GetArrayLength() const
TClass * GetClass() const
static TClass * Class()
virtual std::size_t GetAlignment() const
Returns the alignment of this element in bytes.
void Update(const TClass *oldcl, TClass *newcl)
Update the TClass pointer cached in this object.
TClass * fClass
Not Owned.
TStreamerElement * fElem
Not Owned.
Describes a persistent version of a class.
Int_t fNVirtualInfoLoc
! Number of virtual info location to update.
Int_t fOnFileClassVersion
!Class version identifier as stored on file.
Int_t GetSize() const override
Return total size of all persistent elements of the class (with offsets).
Int_t GetClassVersion() const override
void Destructor(void *p, Bool_t dtorOnly=kFALSE) override
Emulated destructor for this class.
TVirtualStreamerInfo * GenerateInfoForPair(const std::string &pairclassname, bool silent, size_t hint_pair_offset, size_t hint_pair_size) override
Generate the TClass and TStreamerInfo for the requested pair.
TClassStreamer * GenExplicitClassStreamer(const ::ROOT::Detail::TCollectionProxyInfo &info, TClass *cl) override
Generate class streamer from static functions.
TVirtualCollectionProxy * GenEmulatedProxy(const char *class_name, Bool_t silent) override
Generate emulated collection proxy for a given class.
Int_t fNfulldata
!number of elements
TCompInfo * fComp
![fNslots with less than fElements->GetEntries()*1.5 used] Compiled info
TVirtualCollectionProxy * GenExplicitProxy(const ::ROOT::Detail::TCollectionProxyInfo &info, TClass *cl) override
Generate proxy from static functions.
T GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const
Return value of element i in object at pointer.
TStreamerInfoActions::TActionSequence * fWriteMemberWiseVecPtr
! List of write action resulting from the compilation for use in member wise streaming.
TClassStreamer * GenEmulatedClassStreamer(const char *class_name, Bool_t silent) override
Generate emulated class streamer for a given collection class.
Int_t GenerateHeaderFile(const char *dirname, const TList *subClasses=nullptr, const TList *extrainfos=nullptr) override
Generate header file for the class described by this TStreamerInfo the function is called by TFile::M...
TStreamerInfoActions::TActionSequence * fReadText
! List of text read action resulting from the compilation, used for JSON.
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.
TClass * GetActualClass(const void *obj) const override
Assuming that obj points to (the part of) an object that is of the type described by this streamerInf...
TStreamerElement * GetStreamerElementReal(Int_t i, Int_t j) const
Obsolete: this routine is obsolete and should not longer be used.
TClass * IsA() const override
TClass * fClass
!pointer to class
Bool_t MatchLegacyCheckSum(UInt_t checksum) const
Return true if the checksum passed as argument is one of the checksum value produced by the older che...
~TStreamerInfo() override
TStreamerInfo dtor.
TCompInfo ** fCompOpt
![fNdata]
void TagFile(TFile *fFile) override
Mark the classindex of the current file as using this TStreamerInfo.
Int_t GetNewType(Int_t id) const
void SetClass(TClass *cl) override
Replace the TClass this streamerInfo is pointing to (belongs to)
UInt_t fCheckSum
Checksum of original class.
void Streamer(TBuffer &) override
Stream an object of class TStreamerInfo.
Int_t GetSizeElements() const
Return total size of all persistent elements of the class use GetSize if you want to get the real siz...
TClass * GetClass() const override
static std::atomic< Int_t > fgCount
Number of TStreamerInfo instances.
T GetTypedValueClones(TClonesArray *clones, Int_t i, Int_t j, Int_t k, Int_t eoffset) const
UInt_t GenerateIncludes(FILE *fp, char *inclist, const TList *extrainfos)
Add to the header file, the #include need for this class.
void ComputeSize()
Compute total size of all persistent elements of the class.
Int_t fNumber
!Unique identifier
void PrintValueSTL(const char *name, TVirtualCollectionProxy *cont, Int_t i, Int_t eoffset, Int_t lenmax=1000) const
Print value of element i in 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.
static TClass * Class()
static TClass * Class()
Basic string class.
Definition TString.h:137
void ToLower()
Change string to lower-case.
Definition TString.cxx:1190
void Clear()
Clear string without changing its capacity.
Definition TString.cxx:1242
const char * Data() const
Definition TString.h:385
@ kTrailing
Definition TString.h:283
TString & Append(const char *cs)
Definition TString.h:582
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:2460
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition TString.cxx:2438
static TClass * Class()
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:642
virtual const char * BaseName(const char *pathname)
Base name of a file name. Base name of /user/root is root.
Definition TSystem.cxx:949
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 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 TClass * GetValueClass() const =0
If the value type is a user-defined class, return a pointer to the TClass representing the value type...
virtual Int_t GetCollectionType() const =0
Return the type of the proxied collection (see enumeration TClassEdit::ESTLType)
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)
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
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:44
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:36
@ 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>