Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TStreamerInfo.cxx
Go to the documentation of this file.
1// @(#)root/io:$Id$
2// Author: Rene Brun 12/10/2000
3
4/*************************************************************************
5 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12/** \class TStreamerInfo
13 \ingroup IO
14
15Describes a persistent version of a class.
16
17A ROOT file contains the list of TStreamerInfo objects for all the
18class versions written to this file.
19When reading a file, all the TStreamerInfo objects are read back in
20memory and registered to the TClass list of TStreamerInfo.
21One can see the list and contents of the TStreamerInfo on a file
22with, e.g.,
23~~~{.cpp}
24 TFile f("myfile.root");
25 f.ShowStreamerInfo();
26~~~
27A TStreamerInfo is a list of TStreamerElement objects (one per data
28member or base class).
29When streaming an object, the system (TClass) loops on all the
30TStreamerElement objects and calls the appropriate function for each
31element type.
32*/
33
34#include "TStreamerInfo.h"
35#include "TFile.h"
36#include "TROOT.h"
37#include "TClonesArray.h"
38#include "TStreamerElement.h"
39#include "TClass.h"
40#include "TClassEdit.h"
41#include "TClassTable.h"
42#include "TDataMember.h"
43#include "TDataType.h"
44#include "TRealData.h"
45#include "TBaseClass.h"
46#include "TBuffer.h"
47#include "TArrayC.h"
48#include "TArrayI.h"
49#include "TArrayF.h"
50#include "TArrayD.h"
51#include "TArrayS.h"
52#include "TArrayL.h"
53#include "TError.h"
54#include "TEnum.h"
55#include "TRef.h"
56#include "TProcessID.h"
57#include "TSystem.h"
58#include "TObjString.h"
59#include "snprintf.h"
60
61#include "TStreamer.h"
65#include "TInterpreter.h"
66
67#include "TMemberInspector.h"
68
69#include "TMakeProject.h"
70
71#include "TSchemaRuleSet.h"
72#include "TSchemaRule.h"
73
74#include "TVirtualMutex.h"
75
78
79#include <memory>
80#include <algorithm>
81#include <array>
82#include <new>
83
84std::atomic<Int_t> TStreamerInfo::fgCount{0};
85
86const Int_t kMaxLen = 1024;
87
88
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 Riostream.h in case of an STL container
4247 if (!incRiostream && element->InheritsFrom(TStreamerSTL::Class())) {
4249 TMakeProject::AddInclude( fp, "Riostream.h", kFALSE, inclist);
4250 }
4251
4252 //get include file name if any
4253 const char *include = element->GetInclude();
4254 if (!include[0]) continue;
4255
4256 Bool_t greater = (include[0]=='<');
4257 include++;
4258
4259 if (strncmp(include,"include/",8)==0) {
4260 include += 8;
4261 }
4262 if (strncmp(include,"include\\",9)==0) {
4263 include += 9;
4264 }
4265 if (TClassEdit::IsStdPair(element->GetTypeName())) {
4266 TMakeProject::AddInclude( fp, "utility", kTRUE, inclist);
4267 } else if (strncmp(element->GetTypeName(),"auto_ptr<",std::char_traits<char>::length("auto_ptr<"))==0) {
4268 TMakeProject::AddInclude( fp, "memory", kTRUE, inclist);
4269 } else {
4273 }
4274
4275 if (strchr(element->GetTypeName(),'<')) {
4276 // This is a template, we need to check the template parameter.
4278 }
4279 }
4280 return ninc;
4281}
4282
4283////////////////////////////////////////////////////////////////////////////////
4284/// Generate header file for the class described by this TStreamerInfo
4285/// the function is called by TFile::MakeProject for each class in the file
4286
4288{
4289 // if (fClassVersion == -4) return 0;
4290 if ((fClass && fClass->GetCollectionType()) || TClassEdit::IsSTLCont(GetName())) return 0;
4291 if (TClassEdit::IsStdPair(GetName())) return 0;
4292 if (strncmp(GetName(),"auto_ptr<",std::char_traits<char>::length("auto_ptr<"))==0) return 0;
4293
4295 if (cl) {
4296 if (cl->HasInterpreterInfo()) return 0; // skip known classes
4297 }
4299 if (strchr(GetName(),':')) {
4300 UInt_t len = strlen(GetName());
4301 UInt_t nest = 0;
4302 UInt_t scope = 0;
4303 for(UInt_t i=len; i>0; --i) {
4304 switch(GetName()[i]) {
4305 case '>': ++nest; if (scope==0) { isTemplate = kTRUE; } break;
4306 case '<': --nest; break;
4307 case ':':
4308 if (nest==0 && GetName()[i-1]==':') {
4309 // We have a scope
4310 TString nsname(GetName(), i-1);
4311 cl = gROOT->GetClass(nsname);
4312 if (cl && (cl->Size()!=0 || (cl->Size()==0 && !cl->HasInterpreterInfo() /*empty 'base' class on file*/))) {
4313 // This class is actually nested.
4314 return 0;
4315 } else if (cl == 0 && extrainfos != 0) {
4317 if (clinfo && clinfo->GetClassVersion() == -5) {
4318 // This class is actually nested.
4319 return 0;
4320 }
4321 }
4322 ++scope;
4323 }
4324 break;
4325 }
4326 }
4327 }
4329
4330 if (gDebug) printf("generating code for class %s\n",GetName());
4331
4332 // Open the file
4333
4336 filename.Form("%s/%s.h",dirname,headername.Data());
4337
4338 FILE *fp = fopen(filename.Data(),"w");
4339 if (!fp) {
4340 Error("MakeProject","Cannot open output file:%s\n",filename.Data());
4341 return 0;
4342 }
4343
4344 filename.Form("%s/%sProjectHeaders.h",dirname,gSystem->BaseName(dirname));
4345 FILE *allfp = fopen(filename.Data(),"a");
4346 if (!allfp) {
4347 Error("MakeProject","Cannot open output file:%s\n",filename.Data());
4348 fclose(fp);
4349 return 0;
4350 }
4351 fprintf(allfp,"#include \"%s.h\"\n", headername.Data());
4352 fclose(allfp);
4353
4354 char *inclist = new char[50000];
4355 inclist[0] = 0;
4356
4357 // Generate class header.
4358 TDatime td;
4359 fprintf(fp,"//////////////////////////////////////////////////////////\n");
4360 fprintf(fp,"// This class has been generated by TFile::MakeProject\n");
4361 fprintf(fp,"// (%s by ROOT version %s)\n",td.AsString(),gROOT->GetVersion());
4362 fprintf(fp,"// from the StreamerInfo in file %s\n",gDirectory->GetFile()->GetName());
4363 fprintf(fp,"//////////////////////////////////////////////////////////\n");
4364 fprintf(fp,"\n");
4365 fprintf(fp,"\n");
4366 fprintf(fp,"#ifndef %s_h\n",headername.Data());
4367 fprintf(fp,"#define %s_h\n",headername.Data());
4369 fprintf(fp,"\n");
4370
4372 if (subClasses) {
4375 while ((subinfo = (TStreamerInfo*)subnext())) {
4376 subinfo->GenerateIncludes(fp, inclist, extrainfos);
4377 }
4378 }
4379 fprintf(fp,"\n");
4380
4381 TString sourcename; sourcename.Form( "%s/%sProjectSource.cxx", dirname, gSystem->BaseName(dirname) );
4382 FILE *sfp = fopen( sourcename.Data(), "a" );
4383 if (sfp) {
4385 } else {
4386 Error("GenerateHeaderFile","Could not open %s for appending",sourcename.Data());
4387 }
4389
4390 fprintf(fp,"#endif\n");
4391
4392 delete [] inclist;
4393 fclose(fp);
4394 if (sfp) fclose(sfp);
4395 return 1;
4396}
4397
4398////////////////////////////////////////////////////////////////////////////////
4399/// Compute data member offset.
4400/// Return pointer to the Streamer function if one exists
4401
4403{
4405 char dmbracket[256];
4406 snprintf(dmbracket,255,"%s[",dm->GetName());
4408 if (!fClass->IsLoaded()) {
4409 // If the 'class' is not loaded, we do not have a TClass bootstrap and thus
4410 // the 'RealData' might not have enough information because of the lack
4411 // of proper ShowMember implementation.
4412 if (! (dm->Property() & kIsStatic) ) {
4413 // Give an offset only to non-static members.
4414 offset = dm->GetOffset();
4415 }
4416 }
4417 TRealData *rdm;
4418 while ((rdm = (TRealData*)nextr())) {
4419 char *rdmc = (char*)rdm->GetName();
4420 //next statement required in case a class and one of its parent class
4421 //have data members with the same name
4422 if (dm->IsaPointer() && rdmc[0] == '*') rdmc++;
4423
4424 if (rdm->GetDataMember() != dm) continue;
4425 if (strcmp(rdmc,dm->GetName()) == 0) {
4426 offset = rdm->GetThisOffset();
4427 streamer = rdm->GetStreamer();
4428 break;
4429 }
4430 if (strcmp(rdm->GetName(),dm->GetName()) == 0) {
4431 if (rdm->IsObject()) {
4432 offset = rdm->GetThisOffset();
4433 streamer = rdm->GetStreamer();
4434 break;
4435 }
4436 }
4437 if (strstr(rdm->GetName(),dmbracket)) {
4438 offset = rdm->GetThisOffset();
4439 streamer = rdm->GetStreamer();
4440 break;
4441 }
4442 }
4443 return offset;
4444}
4445
4446////////////////////////////////////////////////////////////////////////////////
4447/// Return the offset of the data member as indicated by this StreamerInfo.
4448
4450{
4451 if (elementName == 0) return 0;
4452
4453 Int_t offset = 0;
4455 if (elem) offset = elem->GetOffset();
4456
4457 return offset;
4458}
4459
4460////////////////////////////////////////////////////////////////////////////////
4461/// Return total size of all persistent elements of the class (with offsets).
4462
4464{
4465 return fSize;
4466}
4467
4468////////////////////////////////////////////////////////////////////////////////
4469/// Return total size of all persistent elements of the class
4470/// use GetSize if you want to get the real size in memory.
4471
4473{
4474 TIter next(fElements);
4476 Int_t asize = 0;
4477 while ((element = (TStreamerElement*)next())) {
4478 asize += element->GetSize();
4479 }
4480 return asize;
4481}
4482
4483////////////////////////////////////////////////////////////////////////////////
4484/// Return the StreamerElement of "datamember" inside our
4485/// class or any of its base classes.
4486///
4487/// The offset information
4488/// contained in the StreamerElement is related to its immediately
4489/// containing class, so we return in 'offset' the offset inside
4490/// our class.
4491
4493{
4494 if (!fElements) {
4495 return 0;
4496 }
4497
4498 // Look first at the data members and base classes
4499 // of our class.
4501 if (element) {
4502 offset = element->GetOffset();
4503 return element;
4504 }
4505
4506 // Not found, so now try the data members and base classes
4507 // of the base classes of our class.
4508 if (fClass->HasDataMemberInfo()) {
4509 // Our class has a dictionary loaded, use it to search the base classes.
4511 TBaseClass* base = 0;
4512 TClass* base_cl = 0;
4513 Int_t base_offset = 0;
4514 Int_t local_offset = 0;
4516 // Iterate on list of base classes.
4517 while ((base = (TBaseClass*) nextb())) {
4518 base_cl = TClass::GetClass(base->GetName());
4520 if (!base_cl || !base_element) {
4521 continue;
4522 }
4523 base_offset = base_element->GetOffset();
4525 if (element) {
4527 return element;
4528 }
4529 }
4530 } else {
4531 // Our class's dictionary is not loaded. Search through the base class streamer elements.
4532 TIter next(fElements);
4534 while ((curelem = (TStreamerElement*) next())) {
4535 if (curelem->InheritsFrom(TStreamerBase::Class())) {
4536 TClass* baseClass = curelem->GetClassPointer();
4537 if (!baseClass) {
4538 continue;
4539 }
4540 Int_t base_offset = curelem->GetOffset();
4541 Int_t local_offset = 0;
4543 if (baseClass->Property() & kIsAbstract) {
4544 baseInfo = (TStreamerInfo*)baseClass->GetStreamerInfoAbstractEmulated();
4545 } else {
4546 baseInfo = (TStreamerInfo*)baseClass->GetStreamerInfo();
4547 }
4548 if (baseInfo) element = baseInfo->GetStreamerElement(datamember, local_offset);
4549 if (element) {
4551 return element;
4552 }
4553 }
4554 }
4555 }
4556 return 0;
4557}
4558
4559////////////////////////////////////////////////////////////////////////////////
4560/// <b>Obsolete</b>: this routine is obsolete and should not longer be used.
4561///
4562/// TStreamerInfo holds two types of data structures
4563/// - TObjArray* fElements; containing the list of all TStreamerElement
4564/// objects for this class version.
4565/// - ULong_t* fElem; containing the preprocessed information
4566/// by TStreamerInfo::Compile In case consecutive data members
4567/// are of the same type, the Compile function declares the consecutive
4568/// elements as one single element in fElems.
4569///
4570/// Example with the class TAttLine:
4571/// ~~~{.cpp}
4572/// TClass::GetClass("TAttLine")->GetStreamerInfo()->ls(); produces;
4573/// StreamerInfo for class: TAttLine, version=1
4574/// short fLineColor offset= 4 type= 2 line color
4575/// short fLineStyle offset= 6 type= 2 line style
4576/// short fLineWidth offset= 8 type= 2 line width
4577/// i= 0, fLineColor type= 22, offset= 4, len=3, method=0
4578/// ~~~
4579/// For I/O implementations (eg. XML) , one has to know the original name
4580/// of the data member. This function can be used to return a pointer
4581/// to the original TStreamerElement object corresponding to the j-th
4582/// element of a compressed array in fElems.
4583/// Parameters description:
4584/// - i: the serial number in array fElem
4585/// - j: the element number in the array of consecutive types
4586/// In the above example the class TAttLine has 3 consecutive data members
4587/// of the same type "short". Compile makes one single array of 3 elements.
4588/// To access the TStreamerElement for the second element
4589/// of this array, one can call:
4590/// ~~~{.cpp}
4591/// auto el = GetStreamerElementReal(0,1);
4592/// auto membername = el->GetName();
4593/// ~~~
4594/// This function is typically called from TBuffer, TXmlBuffer.
4595
4597{
4598 ::Obsolete("TStreamerInfo::GetStreamerElementReal", "v5-34-20", "v6-00-02");
4599
4600 if (i < 0 || i >= fNdata) return 0;
4601 if (j < 0) return 0;
4602 if (!fElements) return 0;
4604 if (!se) return 0;
4606 for (Int_t ise=0;ise < nelems;ise++) {
4607 if (se != (TStreamerElement*)fElements->UncheckedAt(ise)) continue;
4608 if (ise+j >= nelems) return 0;
4610 }
4611 return 0;
4612}
4613
4614////////////////////////////////////////////////////////////////////////////////
4615/// Get the value from inside a collection.
4616
4617template <typename T>
4619{
4620 if (type>=kConv && type<kSTL) {
4621 type -= kConv;
4622 }
4623 switch (type) {
4624 // basic types
4625 case kBool: {Bool_t *val = (Bool_t*)ladd; return T(*val);}
4626 case kChar: {Char_t *val = (Char_t*)ladd; return T(*val);}
4627 case kShort: {Short_t *val = (Short_t*)ladd; return T(*val);}
4628 case kInt: {Int_t *val = (Int_t*)ladd; return T(*val);}
4629 case kLong: {Long_t *val = (Long_t*)ladd; return T(*val);}
4630 case kLong64: {Long64_t *val = (Long64_t*)ladd; return T(*val);}
4631 case kFloat: {Float_t *val = (Float_t*)ladd; return T(*val);}
4632 case kFloat16: {Float_t *val = (Float_t*)ladd; return T(*val);}
4633 case kDouble: {Double_t *val = (Double_t*)ladd; return T(*val);}
4634 case kDouble32: {Double_t *val = (Double_t*)ladd; return T(*val);}
4635 case kUChar: {UChar_t *val = (UChar_t*)ladd; return T(*val);}
4636 case kUShort: {UShort_t *val = (UShort_t*)ladd; return T(*val);}
4637 case kUInt: {UInt_t *val = (UInt_t*)ladd; return T(*val);}
4638 case kULong: {ULong_t *val = (ULong_t*)ladd; return T(*val);}
4639#if defined(_MSC_VER) && (_MSC_VER <= 1200)
4640 case kULong64: {Long64_t *val = (Long64_t*)ladd; return T(*val);}
4641#else
4642 case kULong64: {ULong64_t *val= (ULong64_t*)ladd; return T(*val);}
4643#endif
4644 case kBits: {UInt_t *val = (UInt_t*)ladd; return T(*val);}
4645
4646 // array of basic types array[8]
4647 case kOffsetL + kBool: {Bool_t *val = (Bool_t*)ladd; return T(val[k]);}
4648 case kOffsetL + kChar: {Char_t *val = (Char_t*)ladd; return T(val[k]);}
4649 case kOffsetL + kShort: {Short_t *val = (Short_t*)ladd; return T(val[k]);}
4650 case kOffsetL + kInt: {Int_t *val = (Int_t*)ladd; return T(val[k]);}
4651 case kOffsetL + kLong: {Long_t *val = (Long_t*)ladd; return T(val[k]);}
4652 case kOffsetL + kLong64: {Long64_t *val = (Long64_t*)ladd; return T(val[k]);}
4653 case kOffsetL + kFloat: {Float_t *val = (Float_t*)ladd; return T(val[k]);}
4654 case kOffsetL + kFloat16: {Float_t *val = (Float_t*)ladd; return T(val[k]);}
4655 case kOffsetL + kDouble: {Double_t *val = (Double_t*)ladd; return T(val[k]);}
4656 case kOffsetL + kDouble32:{Double_t *val = (Double_t*)ladd; return T(val[k]);}
4657 case kOffsetL + kUChar: {UChar_t *val = (UChar_t*)ladd; return T(val[k]);}
4658 case kOffsetL + kUShort: {UShort_t *val = (UShort_t*)ladd; return T(val[k]);}
4659 case kOffsetL + kUInt: {UInt_t *val = (UInt_t*)ladd; return T(val[k]);}
4660 case kOffsetL + kULong: {ULong_t *val = (ULong_t*)ladd; return T(val[k]);}
4661#if defined(_MSC_VER) && (_MSC_VER <= 1200)
4662 case kOffsetL + kULong64: {Long64_t *val = (Long64_t*)ladd; return T(val[k]);}
4663#else
4664 case kOffsetL + kULong64:{ULong64_t *val= (ULong64_t*)ladd; return T(val[k]);}
4665#endif
4666
4667#define READ_ARRAY(TYPE_t) \
4668 { \
4669 Int_t sub_instance, index; \
4670 Int_t instance = k; \
4671 if (len) { \
4672 index = instance / len; \
4673 sub_instance = instance % len; \
4674 } else { \
4675 index = instance; \
4676 sub_instance = 0; \
4677 } \
4678 TYPE_t **val =(TYPE_t**)(ladd); \
4679 return T((val[sub_instance])[index]); \
4680 }
4681
4682 // pointer to an array of basic types array[n]
4683 case (unsigned)kOffsetP + kBool_t: READ_ARRAY(Bool_t)
4684 case (unsigned)kOffsetP + kChar_t: READ_ARRAY(Char_t)
4685 case (unsigned)kOffsetP + kShort_t: READ_ARRAY(Short_t)
4686 case (unsigned)kOffsetP + kInt_t: READ_ARRAY(Int_t)
4687 case (unsigned)kOffsetP + kLong_t: READ_ARRAY(Long_t)
4688 case (unsigned)kOffsetP + kLong64_t: READ_ARRAY(Long64_t)
4689 case (unsigned)kOffsetP + kFloat16_t:
4690 case (unsigned)kOffsetP + kFloat_t: READ_ARRAY(Float_t)
4691 case (unsigned)kOffsetP + kDouble32_t:
4692 case (unsigned)kOffsetP + kDouble_t: READ_ARRAY(Double_t)
4693 case (unsigned)kOffsetP + kUChar_t: READ_ARRAY(UChar_t)
4694 case (unsigned)kOffsetP + kUShort_t: READ_ARRAY(UShort_t)
4695 case (unsigned)kOffsetP + kUInt_t: READ_ARRAY(UInt_t)
4696 case (unsigned)kOffsetP + kULong_t: READ_ARRAY(ULong_t)
4697#if defined(_MSC_VER) && (_MSC_VER <= 1200)
4698 case (unsigned)kOffsetP + kULong64_t: READ_ARRAY(Long64_t)
4699#else
4700 case (unsigned)kOffsetP + kULong64_t: READ_ARRAY(ULong64_t)
4701#endif
4702
4703 // array counter //[n]
4704 case kCounter: {Int_t *val = (Int_t*)ladd; return T(*val);}
4705 }
4706 return 0;
4707}
4708
4709
4710
4711template Double_t TStreamerInfo::GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const;
4712template Long64_t TStreamerInfo::GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const;
4713template LongDouble_t TStreamerInfo::GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const;
4714
4715////////////////////////////////////////////////////////////////////////////////
4716/// Return value of element i in object at pointer.
4717/// The function may be called in two ways:
4718/// - method1 len < 0: i is assumed to be the TStreamerElement number i in StreamerInfo
4719/// - method2 len >= 0: i is the type, address of variable is directly pointer.
4720
4721template <typename T>
4723{
4724 char *ladd;
4725 Int_t atype;
4726 if (len >= 0) {
4727 ladd = pointer;
4728 atype = i;
4729 } else {
4730 if (i < 0) return 0;
4731 ladd = pointer + fCompFull[i]->fOffset;
4732 atype = fCompFull[i]->fNewType;
4734 if (atype == kSTL) {
4736 if (newClass == 0) {
4738 }
4739 TClass *innerClass = newClass->GetCollectionProxy()->GetValueClass();
4740 if (innerClass) {
4741 return 0; // We don't know which member of the class we would want.
4742 } else {
4743 TVirtualCollectionProxy *proxy = newClass->GetCollectionProxy();
4744 // EDataType is a subset of TStreamerInfo::EReadWrite
4747 Int_t nc = proxy->Size();
4748 if (j >= nc) return 0;
4749 char *element_ptr = (char*)proxy->At(j);
4751 }
4752 }
4753 }
4755}
4756
4757////////////////////////////////////////////////////////////////////////////////
4758
4759template Double_t TStreamerInfo::GetTypedValueClones<Double_t>(TClonesArray *clones, Int_t i, Int_t j, int k, Int_t eoffset) const;
4762
4763template <typename T>
4765{
4766 // return value of element i in object number j in a TClonesArray and eventually
4767 // element k in a sub-array.
4768
4769 Int_t nc = clones->GetEntriesFast();
4770 if (j >= nc) return 0;
4771
4772 char *pointer = (char*)clones->UncheckedAt(j);
4773 char *ladd = pointer + eoffset + fCompFull[i]->fOffset;
4774 return GetTypedValueAux<T>(fCompFull[i]->fType,ladd,k,((TStreamerElement*)fCompFull[i]->fElem)->GetArrayLength());
4775}
4776
4780
4781////////////////////////////////////////////////////////////////////////////////
4782/// Return value of element i in object number j in an STL container and eventually
4783/// element k in a sub-array.
4784
4785template <typename T>
4787{
4788 Int_t nc = cont->Size();
4789 if (j >= nc) return 0;
4790
4791 char *pointer = (char*)cont->At(j);
4792 char *ladd = pointer + eoffset + fCompFull[i]->fOffset;
4793 return GetTypedValueAux<T>(fCompFull[i]->fType,ladd,k,((TStreamerElement*)fCompFull[i]->fElem)->GetArrayLength());
4794}
4795
4799
4800////////////////////////////////////////////////////////////////////////////////
4801/// Return value of element i in object number j in a pointer to STL container and eventually
4802/// element k in a sub-array.
4803
4804template <typename T>
4806{
4807 Int_t nc = cont->Size();
4808
4809 if (j >= nc) return 0;
4810
4811 char **ptr = (char**)cont->At(j);
4812 char *pointer = *ptr;
4813
4814 char *ladd = pointer + eoffset + fCompFull[i]->fOffset;
4815 return GetTypedValueAux<T>(fCompFull[i]->fType,ladd,k,((TStreamerElement*)fCompFull[i]->fElem)->GetArrayLength());
4816}
4817
4818////////////////////////////////////////////////////////////////////////////////
4819/// Insert new members as expressed in the array of TSchemaRule(s).
4820
4821void TStreamerInfo::InsertArtificialElements(std::vector<const ROOT::TSchemaRule*> &rules)
4822{
4823 if (rules.empty()) return;
4824
4825 TIter next(fElements);
4826 UInt_t count = 0;
4827
4828 for(auto rule : rules) {
4829 if( rule->IsRenameRule() || rule->IsAliasRule() )
4830 continue;
4831 next.Reset();
4833 while ((element = (TStreamerElement*) next())) {
4834 if ( rule->HasTarget( element->GetName() ) ) {
4835
4836 // Check whether this is an 'attribute' rule.
4837 if ( rule->GetAttributes()[0] != 0 ) {
4838 TString attr( rule->GetAttributes() );
4839 attr.ToLower();
4840 if (attr.Contains("owner")) {
4841 if (attr.Contains("notowner")) {
4843 } else {
4845 }
4846 }
4847
4848 }
4849 break;
4850 }
4851 }
4852
4853 auto canIgnore = [](const ROOT::TSchemaRule *r) {
4854 if (r->GetAttributes()[0] != 0) {
4855 TString attr(r->GetAttributes());
4856 attr.ToLower();
4857 return attr.Contains("canignore");
4858 } else
4859 return false;
4860 };
4861 // NOTE: Before adding the rule we should check that the source do
4862 // existing in this StreamerInfo.
4863 const TObjArray *sources = rule->GetSource();
4864 if (sources)
4866 auto source_element = dynamic_cast<TStreamerElement *>(GetElements()->FindObject(src->GetName()));
4867 if (!source_element) {
4868 // It might still be in one the base classes.
4869 if (fClass->GetListOfRealData() && !fClass->GetListOfRealData()->FindObject(src->GetName())) {
4870 // Missing source.
4871 if (!canIgnore(rule)) {
4873 rule->AsString(ruleStr);
4874 Warning("InsertArtificialElements",
4875 "For class %s in StreamerInfo %d is missing the source data member `%s` when trying to "
4876 "apply the "
4877 "rule:\n %s",
4878 GetName(), GetClassVersion(), src->GetName(), ruleStr.Data());
4879 }
4880 rule = nullptr;
4881 break;
4882 }
4883 } else {
4884 // The source exists, let's check if it has the expected type.
4886 if ((memClass != source_element->GetNewClass() || memType != source_element->GetNewType()) &&
4888 const char *dim = src->GetDimensions();
4890 rule->AsString(ruleStr);
4891 auto cl = source_element->GetNewClass();
4893 if (memClass != cl) {
4894 classmsg = "and the memory TClass is \"";
4895 classmsg += cl ? cl->GetName() : "nullptr";
4896 classmsg += "\" while the rule needed \"";
4897 classmsg += memClass ? memClass->GetName() : "nullptr";
4898 classmsg += "\"";
4899 }
4900 Error("InsertArtificialElements",
4901 "For class %s in StreamerInfo %d a rule has conflicting type for the source \"%s %s%s\",\n"
4902 " The TStreamerElement has memory type %d (needed %d) %s:\n %s",
4903 GetName(), GetClassVersion(), src->GetTypeForDeclaration().Data(), src->GetName(),
4904 dim && dim[0] ? dim : "", source_element->GetNewType(), memType, classmsg.Data(),
4905 ruleStr.Data());
4906 rule = nullptr;
4907 break;
4908 }
4909 }
4910 }
4911
4912 if (!rule) continue;
4913
4915 std::vector<TStreamerArtificial*> toAdd;
4916
4917 if (rule->GetTarget()==0) {
4919 newName.Form("%s_rule%d",fClass->GetName(),count);
4923 "void");
4925 newel->SetReadFunc( rule->GetReadFunctionPointer() );
4926 newel->SetReadRawFunc( rule->GetReadRawFunctionPointer() );
4927 toAdd.push_back(newel);
4928 } else {
4929 toAdd.reserve(rule->GetTarget()->GetEntriesFast());
4930 TObjString * objstr = (TObjString*)(rule->GetTarget()->At(0));
4931 if (objstr) {
4932 TString newName = objstr->String();
4934 if ( TDataMember* dm = fClass->GetDataMember( newName ) ) {
4937 TStreamerInfo::kArtificial, dm->GetTypeName());
4938 newel->SetReadFunc( rule->GetReadFunctionPointer() );
4939 newel->SetReadRawFunc( rule->GetReadRawFunctionPointer() );
4940 toAdd.push_back(newel);
4941 } else {
4942 // This would be a completely new member (so it would need to be cached)
4943 // TOBEDONE
4944 }
4945 for(Int_t other = 1; other < rule->GetTarget()->GetEntriesFast(); ++other) {
4946 objstr = (TObjString*)(rule->GetTarget()->At(other));
4947 if (objstr) {
4948 newName = objstr->String();
4949 if ( TDataMember* dm = fClass->GetDataMember( newName ) ) {
4952 TStreamerInfo::kArtificial, dm->GetTypeName());
4953 toAdd.push_back(newel);
4954 }
4955 }
4956 }
4957 } // For each target of the rule
4958 }
4959 // Now find where with need to add them
4960 TIter s_iter(rule->GetSource());
4961 Int_t loc = -1;
4962 while( TObjString *s = (TObjString*)s_iter() ) {
4963 for(Int_t i = fElements->GetLast(); i >= 0 && (i+1) >= loc; --i) {
4964 if (s->String() == fElements->UncheckedAt(i)->GetName()) {
4965 if (loc == -1 || (i+1)>loc) {
4966 loc = i+1;
4967 }
4968 }
4969 }
4970 }
4971 if (loc == -1) {
4972 // Verify if the last one is not 'skipped'.
4973 for(Int_t i = fElements->GetLast(); i >= 0 && (i+1) >= loc; --i) {
4976 break;
4977 }
4978 loc = i;
4979 }
4980 }
4981 if (loc == -1) {
4982 for(auto &el : toAdd) {
4983 fElements->Add(el);
4984 }
4985 } else {
4987 }
4988 } // None of the target of the rule are on file.
4989}
4990
4991////////////////////////////////////////////////////////////////////////////////
4992/// List the TStreamerElement list and also the precomputed tables
4993/// if option contains the string "incOrig", also prints the original
4994/// (non-optimized elements in the list of compiled elements.
4995
4997{
4998 if (fClass && (fName != fClass->GetName())) {
4999 if (fClass->IsVersioned()) {
5000 Printf("\nStreamerInfo for conversion to %s from: %s, version=%d, checksum=0x%x",fClass->GetName(),GetName(),fClassVersion,GetCheckSum());
5001 } else {
5002 Printf("\nStreamerInfo for conversion to %s from: %s, checksum=0x%x",fClass->GetName(),GetName(),GetCheckSum());
5003 }
5004 } else {
5005 if (!fClass || fClass->IsVersioned()) {
5006 Printf("\nStreamerInfo for class: %s, version=%d, checksum=0x%x",GetName(),fClassVersion,GetCheckSum());
5007 } else {
5008 Printf("\nStreamerInfo for class: %s, checksum=0x%x",GetName(),GetCheckSum());
5009 }
5010 }
5011
5012 if (fElements) {
5013 TIter next(fElements);
5014 TObject *obj;
5015 while ((obj = next()))
5016 obj->ls(option);
5017 }
5018 Bool_t noaddr = option && (strstr(option,"noaddr") != nullptr);
5019
5020 if (strstr(option,"full") != 0) {
5021 for (Int_t i=0; i < fNfulldata; ++i) {
5024 element->GetSequenceType(sequenceType);
5025 // by definition of the loop (i+1) <= fNdata
5026 if (sequenceType.Length()) {
5027 sequenceType.Prepend(" [");
5028 sequenceType += "]";
5029 }
5030 Printf(" i=%2d, %-15s type=%3d, offset=%3d, len=%d, method=%ld%s",
5031 i,element->GetName(),fCompFull[i]->fType,fCompFull[i]->fOffset,fCompFull[i]->fLength, (noaddr ? 0 : fCompFull[i]->fMethod),
5032 sequenceType.Data());
5033 }
5034
5035 } else {
5036 Bool_t wantOrig = strstr(option,"incOrig") != 0;
5038 for (Int_t i=0,j=0;i < fNdata;++i,++j) {
5041 element->GetSequenceType(sequenceType);
5042 // by definition of the loop (i+1) <= fNdata
5044 if (optimized) {
5045 // This was optimized.
5046 if (sequenceType.Length() != 0) {
5047 sequenceType += ',';
5048 }
5049 sequenceType += "optimized";
5050 }
5051 if (sequenceType.Length()) {
5052 sequenceType.Prepend(" [");
5053 sequenceType += "]";
5054 }
5055 Printf(" i=%2d, %-15s type=%3d, offset=%3d, len=%d, method=%ld%s",
5056 i,element->GetName(),fCompOpt[i]->fType,fCompOpt[i]->fOffset,fCompOpt[i]->fLength, (noaddr ? 0 : fCompOpt[i]->fMethod),
5057 sequenceType.Data());
5058 if (optimized && wantOrig) {
5059 Bool_t done;
5060 do {
5061 element = (TStreamerElement*)fCompFull[j]->fElem;
5062 element->GetSequenceType(sequenceType);
5063 if (sequenceType.Length()) {
5064 sequenceType.Prepend(" [");
5065 sequenceType += "]";
5066 }
5067 Printf(" j=%2d, %-15s type=%3d, offset=%3d, len=%d, method=%ld%s",
5069 sequenceType.Data());
5070 ++j;
5071 done = j >= fNfulldata || ( (i+1 < fNdata) && fCompOpt[i+1]->fElem == fCompFull[j+1]->fElem );
5072 } while (!done);
5073
5074 }
5075 }
5076 }
5077}
5078
5079////////////////////////////////////////////////////////////////////////////////
5080/// An emulated object is created at address obj, if obj is null we
5081/// allocate memory for the object.
5082
5083void* TStreamerInfo::New(void *obj)
5084{
5085 //???FIX ME: What about varying length array elements?
5086
5087 char* p = (char*) obj;
5088
5089 TIter next(fElements);
5090
5091 if (!p) {
5092 // Allocate and initialize the memory block. Ensure the returned
5093 // storage is aligned to the class alignment requirement.
5094 auto align = fClass->GetClassAlignment();
5095 // Use aligned new (C++17). This will return memory aligned to
5096 // 'align' and can be freed with the matching delete[].
5097 assert(ROOT::Internal::IsValidAlignment(align)); // align must be a power of 2
5098 p = static_cast<char *>(::operator new[](fSize, std::align_val_t(align)));
5099 memset(p, 0, fSize);
5100 }
5101
5102 next.Reset();
5104
5105 for (; element; element = (TStreamerElement*) next()) {
5106
5107 // Skip elements which have not been allocated memory.
5108 if (element->GetOffset() == kMissing) {
5109 continue;
5110 }
5111
5112 // Skip elements for which we do not have any class
5113 // information. FIXME: Document how this could happen.
5114 TClass *cle = element->GetNewClass();
5115 if (!cle)
5116 cle = element->GetClassPointer();
5117 if (!cle)
5118 continue;
5119
5120 char* eaddr = p + element->GetOffset();
5121 Int_t etype = element->GetNewType();
5122 if (etype == TStreamerInfo::kNoType)
5123 etype = element->GetType();
5124
5125 //cle->GetStreamerInfo(); //necessary in case "->" is not specified
5126
5127 switch (etype) {
5128
5129 case kAnyP:
5130 case kObjectP:
5131 case kSTLp:
5132 {
5133 // Initialize array of pointers with null pointers.
5134 char** r = (char**) eaddr;
5135 Int_t len = element->GetArrayLength();
5136 for (Int_t i = 0; i < len; ++i) {
5137 r[i] = 0;
5138 }
5139 }
5140 break;
5141
5142 case kObjectp:
5143 case kAnyp:
5144 {
5145 // If the option "->" is given in the data member comment field
5146 // it is assumed that the object exists before reading data in,
5147 // so we create an object.
5148 if (cle != TClonesArray::Class()) {
5149 void** r = (void**) eaddr;
5150 *r = cle->New();
5151 } else {
5152 // In the case of a TClonesArray, the class name of
5153 // the contained objects must be specified in the
5154 // data member comment in this format:
5155 // TClonesArray* myVar; //->(className)
5156 const char* title = element->GetTitle();
5157 const char* bracket1 = strrchr(title, '(');
5158 const char* bracket2 = strrchr(title, ')');
5159 if (bracket1 && bracket2 && (bracket2 != (bracket1 + 1))) {
5160 Int_t len = bracket2 - (bracket1 + 1);
5161 char* clonesClass = new char[len+1];
5162 clonesClass[0] = '\0';
5164 void** r = (void**) eaddr;
5165 *r = (void*) new TClonesArray(clonesClass);
5166 delete[] clonesClass;
5167 } else {
5168 //Warning("New", "No class name found for TClonesArray initializer in data member comment (expected \"//->(className)\"");
5169 void** r = (void**) eaddr;
5170 *r = (void*) new TClonesArray();
5171 }
5172 }
5173 }
5174 break;
5175
5176 case kBase:
5177 {
5178 if (cle->Property() & kIsAbstract) {
5179 TVirtualStreamerInfo *einfo = cle->GetStreamerInfoAbstractEmulated();
5180 if (einfo) einfo->New(eaddr);
5181 } else {
5182 cle->New(eaddr);
5183 }
5184 break;
5185 }
5186 case kObject:
5187 case kAny:
5188 case kTObject:
5189 case kTString:
5190 case kTNamed:
5191 {
5192 cle->New(eaddr);
5193 }
5194 break;
5195
5196 case kSTL:
5197 {
5198 if (strcmp(element->GetName(),"This")==0 &&
5199 !cle->GetCollectionProxy()) {
5200 // missing information, avoid infinite loop
5201 // by doing nothing ....
5202 } else {
5203 if (cle->GetCollectionProxy())
5204 cle->GetCollectionProxy()->New(eaddr);
5205 else
5206 cle->New(eaddr);
5207 }
5208 }
5209 break;
5210
5211 case kObject + kOffsetL:
5212 case kAny + kOffsetL:
5213 case kTObject + kOffsetL:
5214 case kTString + kOffsetL:
5215 case kTNamed + kOffsetL:
5216 case kSTL + kOffsetL:
5217 {
5218 Int_t size = cle->Size();
5219 char* r = eaddr;
5220 Int_t len = element->GetArrayLength();
5221 for (Int_t i = 0; i < len; ++i, r += size) {
5222 cle->New(r);
5223 }
5224 }
5225 break;
5226
5227 } // switch etype
5228 } // for TIter next(fElements)
5229
5230 for(int nbase = 0; nbase < fNVirtualInfoLoc; ++nbase) {
5231 *(TStreamerInfo**)(p + fVirtualInfoLoc[nbase]) = this;
5232 }
5233 return p;
5234}
5235
5236////////////////////////////////////////////////////////////////////////////////
5237/// An array of emulated objects is created at address ary, if ary is null,
5238/// we allocate memory for the array.
5239
5241{
5242 if (fClass == 0) {
5243 Error("NewArray", "TClass pointer is null!");
5244 return 0;
5245 }
5246
5247 Int_t size = fClass->Size();
5248
5249 char* p = (char*) ary;
5250
5251 // Determine the alignment requirement for the class.
5252 const ArrayCookieLayout layout(fClass);
5253
5254 if (!p) {
5255
5256 Long_t len = nElements * size + layout.headerSize;
5257
5258 // Allocate and initialize the memory block. Request alignment so
5259 // that the raw block starts on an 'align'-boundary; combined with
5260 // the rounded-up header this guarantees dataBegin is also aligned.
5261 p = static_cast<char *>(::operator new[](len, std::align_val_t(layout.align)));
5262 memset(p, 0, len);
5263 }
5264
5265 Long_t* r = (Long_t*)(p + layout.headerSize - layout.cookieSize);
5266 r[0] = size;
5267 r[1] = nElements;
5268 char *dataBegin = p + layout.headerSize;
5269
5270 // Do a placement new for each element.
5271 char *q = dataBegin;
5272 for (Long_t cnt = 0; cnt < nElements; ++cnt) {
5273 New(q);
5274 q += size;
5275 } // for nElements
5276
5277 return dataBegin;
5278}
5279
5280
5281#define DeleteBasicPointer(addr,element,name) \
5282 { \
5283 name **f = (name**)(addr); \
5284 int n = element->GetArrayLength() ? element->GetArrayLength() : 1;\
5285 for(int j=0;j<n;j++) { \
5286 delete [] f[j]; \
5287 f[j] = 0; \
5288 } \
5289 }
5290
5291////////////////////////////////////////////////////////////////////////////////
5292/// Internal part of the destructor.
5293/// Destruct each of the datamembers in the same order
5294/// as the implicit destructor would.
5295
5297{
5298 R__ASSERT(obj != 0);
5299
5300 char *p = (char*)obj;
5301
5303 //for (; ele; ele = (TStreamerElement*) next())
5304 for (Int_t elenum = nelements - 1; elenum >= 0; --elenum) {
5306 if (ele->GetOffset() == kMissing) continue;
5307 char* eaddr = p + ele->GetOffset();
5308
5309 Int_t etype = ele->GetNewType(); // in memory type
5310 if (etype == TStreamerInfo::kNoType)
5311 etype = ele->GetType();
5312
5313 switch(etype) {
5330 }
5331
5332 TClass *cle = ele->GetNewClass(); // in memory type
5333 if (!cle)
5334 cle = ele->GetClassPointer();
5335 if (!cle)
5336 continue;
5337
5338 if (etype == kObjectp || etype == kAnyp) {
5339 // Destroy an array of pre-allocated objects.
5340 Int_t len = ele->GetArrayLength();
5341 if (!len) {
5342 len = 1;
5343 }
5344 void** r = (void**) eaddr;
5345 for (Int_t j = len - 1; j >= 0; --j) {
5346 if (r[j]) {
5347 cle->Destructor(r[j]);
5348 r[j] = 0;
5349 }
5350 }
5351 }
5352
5353 if ((etype == kObjectP || etype == kAnyP || etype == kSTLp) && !ele->TestBit(TStreamerElement::kDoNotDelete)) {
5354 // Destroy an array of pointers to not-pre-allocated objects.
5355 Int_t len = ele->GetArrayLength();
5356 if (!len) {
5357 len = 1;
5358 }
5359 void** r = (void**) eaddr;
5360 for (Int_t j = len - 1; j >= 0; --j) {
5361 if (r[j]) {
5362 cle->Destructor(r[j]);
5363 r[j] = 0;
5364 }
5365 }
5366 }
5367
5368 if (etype == kBase) {
5369 if (cle->Property() & kIsAbstract) {
5370 TVirtualStreamerInfo *einfo = cle->GetStreamerInfoAbstractEmulated();
5371 if (einfo) einfo->Destructor(eaddr, kTRUE);
5372 } else {
5373 cle->Destructor(eaddr, kTRUE);
5374 }
5375 }
5376
5377 if (etype == kObject || etype == kAny ||
5378 etype == kTObject || etype == kTString || etype == kTNamed) {
5379 // A data member is destroyed, but not deleted.
5380 cle->Destructor(eaddr, kTRUE);
5381 }
5382
5383 if (etype == kSTL) {
5384 // A data member is destroyed, but not deleted.
5385 TVirtualCollectionProxy *pr = cle->GetCollectionProxy();
5386 if (!pr) {
5387 if (strcmp(ele->GetName(),"This")==0) {
5388 // missing information, avoid infinite loop
5389 // by doing nothing ....
5390 } else {
5391 cle->Destructor(eaddr, kTRUE);
5392 }
5393 } else {
5394 if (ele->TestBit(TStreamerElement::kDoNotDelete)) {
5395 TVirtualCollectionProxy::TPushPop env(cle->GetCollectionProxy(), eaddr); // used for both this 'clear' and the 'clear' inside destructor.
5396 cle->GetCollectionProxy()->Clear(); // empty the collection without deleting the pointer
5397 pr->Destructor(eaddr, kTRUE);
5398 } else {
5399 pr->Destructor(eaddr, kTRUE);
5400 }
5401 }
5402 }
5403
5404 if (etype == kObject + kOffsetL || etype == kAny + kOffsetL ||
5405 etype == kTObject + kOffsetL || etype == kTString + kOffsetL ||
5406 etype == kTNamed + kOffsetL || etype == kSTL + kOffsetL) {
5407 // For a data member which is an array of objects, we
5408 // destroy the objects, but do not delete them.
5409 Int_t len = ele->GetArrayLength();
5410 Int_t size = cle->Size();
5411 char* r = eaddr + (size * (len - 1));
5412 for (Int_t j = len - 1; j >= 0; --j, r -= size) {
5413 cle->Destructor(r, kTRUE);
5414 }
5415 }
5416 } // iter over elements
5417
5418 if (!dtorOnly) {
5419 // Note: We rely on fClass->GetClassAlignment() being the same than we had
5420 // on construction time.
5421 // However it technically can change but there is no much we can sensibly do to detect it. eg. "allocate object,
5422 // unload library, reload library, destruct object" (but in this case the 'unload' library is meant to/should also
5423 // destruct the object (unload transaction) but this is not always possible) or "allocate emulated object, load
5424 // library, destruct object".
5426 ::operator delete[](p, std::align_val_t(fClass->GetClassAlignment()));
5427 }
5428}
5429
5430////////////////////////////////////////////////////////////////////////////////
5431/// Emulated destructor for this class.
5432///
5433/// An emulated object is destroyed at address p.
5434/// Destruct each of the datamembers in the same order
5435/// as the implicit destructor would.
5436
5438{
5439 // Do nothing if passed a null pointer.
5440 if (obj == 0) return;
5441
5442 char* p = (char*) obj;
5443
5444 if (!dtorOnly && fNVirtualInfoLoc) {
5445 // !dtorOnly is used to filter out the case where this is called for
5446 // a base class or embedded object of the outer most class.
5447 TStreamerInfo *allocator = *(TStreamerInfo**)(p + fVirtualInfoLoc[0]);
5448 if (allocator != this) {
5449
5451
5452 p -= baseoffset;
5453 allocator->DestructorImpl(p, kFALSE);
5454 return;
5455 }
5456 }
5458}
5459
5460////////////////////////////////////////////////////////////////////////////////
5461/// Destroy an array of emulated objects, with optional delete.
5462
5464{
5465 // Do nothing if passed a null pointer.
5466 if (ary == 0) return;
5467
5468 //???FIX ME: What about varying length arrays?
5469
5470 // Recover the cookie layout: the two Long_t values sit in the header
5471 // block immediately before dataBegin, with the same alignment-based
5472 // headerSize that NewArray used.
5473 const ArrayCookieLayout layout(fClass);
5474
5475 Long_t *r = (Long_t *)((char *)ary - layout.cookieSize);
5476 Long_t arrayLen = r[1];
5477 Long_t size = r[0];
5478 char *memBegin = (char *)ary - layout.headerSize;
5479
5480 char* p = ((char*) ary) + ((arrayLen - 1) * size);
5481 for (Long_t cnt = 0; cnt < arrayLen; ++cnt, p -= size) {
5482 // Destroy each element, but do not delete it.
5483 Destructor(p, kTRUE);
5484 } // for arrayItemSize
5485
5486 if (!dtorOnly) {
5487 ::operator delete[](memBegin, std::align_val_t(layout.align));
5488 }
5489}
5490
5491////////////////////////////////////////////////////////////////////////////////
5492/// print value of element i in object at pointer
5493/// The function may be called in two ways:
5494/// -method1 len < 0
5495/// i is assumed to be the TStreamerElement number i in StreamerInfo
5496/// -method2 len >= 0
5497/// i is the type
5498/// address of variable is directly pointer.
5499/// len is the number of elements to be printed starting at pointer.
5500
5501void TStreamerInfo::PrintValue(const char *name, char *pointer, Int_t i, Int_t len, Int_t lenmax) const
5502{
5503 char *ladd;
5505 printf(" %-15s = ",name);
5506
5508 Int_t *count = 0;
5509 if (len >= 0) {
5510 ladd = pointer;
5511 atype = i;
5512 aleng = len;
5513 } else {
5514 if (i < 0) {
5515 if (pointer==0) {
5516 printf("nullptr\n");
5517 } else {
5518 const static TClassRef stringClass("string");
5519 if (fClass == stringClass) {
5520 std::string *st = (std::string*)(pointer);
5521 printf("%s\n",st->c_str());
5522 } else if (fClass == TString::Class()) {
5523 TString *st = (TString*)(pointer);
5524 printf("%s\n",st->Data());
5525 } else {
5526 printf("(%s*)0x%zx\n",GetName(),(size_t)pointer);
5527 }
5528 }
5529 return;
5530 }
5531 ladd = pointer + fCompFull[i]->fOffset;
5532 atype = fCompFull[i]->fNewType;
5533 aleng = fCompFull[i]->fLength;
5534 aElement = (TStreamerElement*)fCompFull[i]->fElem;
5535 count = (Int_t*)(pointer+fCompFull[i]->fMethod);
5536 }
5537 if (aleng > lenmax) aleng = lenmax;
5538
5540 printf("\n");
5541}
5542
5543////////////////////////////////////////////////////////////////////////////////
5544/// Print value of element i in a TClonesArray.
5545
5547{
5548 if (!clones) {printf(" %-15s = \n",name); return;}
5549 printf(" %-15s = ",name);
5550 Int_t nc = clones->GetEntriesFast();
5551 if (nc > lenmax) nc = lenmax;
5552
5555 int aleng = fCompFull[i]->fLength;
5556 if (aleng > lenmax) aleng = lenmax;
5557
5558 for (Int_t k=0;k < nc;k++) {
5559 char *pointer = (char*)clones->UncheckedAt(k);
5560 char *ladd = pointer+offset;
5561 Int_t *count = (Int_t*)(pointer+fCompFull[i]->fMethod);
5562 PrintValueAux(ladd,fCompFull[i]->fNewType,aElement, aleng, count);
5563 if (k < nc-1) printf(", ");
5564 }
5565 printf("\n");
5566}
5567
5568////////////////////////////////////////////////////////////////////////////////
5569/// Print value of element i in an STL container.
5570
5572{
5573 if (!cont) {printf(" %-15s = \n",name); return;}
5574 printf(" %-15s = ",name);
5575 Int_t nc = cont->Size();
5576 if (nc > lenmax) nc = lenmax;
5577
5580 int aleng = fCompFull[i]->fLength;
5581 if (aleng > lenmax) aleng = lenmax;
5582
5583 for (Int_t k=0;k < nc;k++) {
5584 char *pointer = (char*)cont->At(k);
5585 char *ladd = pointer+offset;
5586 Int_t *count = (Int_t*)(pointer+fCompFull[i]->fMethod);
5587 PrintValueAux(ladd,fCompFull[i]->fNewType,aElement, aleng, count);
5588 if (k < nc-1) printf(", ");
5589 }
5590 printf("\n");
5591}
5592
5593////////////////////////////////////////////////////////////////////////////////
5594/// Replace the TClass this streamerInfo is pointing to (belongs to)
5595
5597{
5598 if (newcl) {
5599 // This is mostly (but not only) for the artificial "This" streamerElement for an stl collection.
5601 }
5602 fClass = newcl;
5603}
5604
5605////////////////////////////////////////////////////////////////////////////////
5606/// Stream an object of class TStreamerInfo.
5607
5609{
5610 UInt_t R__s, R__c;
5611 if (R__b.IsReading()) {
5612 Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
5613 fOldVersion = R__v;
5614 if (R__v > 1) {
5615 //R__b.ReadClassBuffer(TStreamerInfo::Class(), this, R__v, R__s, R__c);
5616 R__b.ClassBegin(TStreamerInfo::Class(), R__v);
5617 R__b.ClassMember("TNamed");
5620 R__b.ClassMember("fCheckSum","UInt_t");
5621 R__b >> fCheckSum;
5622 R__b.ClassMember("fClassVersion","Int_t");
5625 R__b.ClassMember("fElements","TObjArray*");
5626 R__b >> fElements;
5627 R__b.ClassEnd(TStreamerInfo::Class());
5628 R__b.SetBufferOffset(R__s+R__c+sizeof(UInt_t));
5632
5633 if (R__b.GetParent() && R__b.GetVersionOwner() < 50000)
5634 {
5635 // In some older files, the type of the TStreamerElement was not
5636 // as we (now) expect.
5639 for (Int_t i = 0; i < nobjects; i++) {
5641 TStreamerElement *rel = 0;
5642 if ( el->IsA() == basic ) {
5643 switch (el->GetType()) {
5644 default: break; /* nothing */
5645 case TStreamerInfo::kObject: /*61*/
5646 rel = new TStreamerObject(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5647 break;
5648 case TStreamerInfo::kAny: /*62*/
5649 rel = new TStreamerObjectAny(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5650 break;
5651 case TStreamerInfo::kObjectp: /* 63 */
5652 rel = new TStreamerObjectPointer(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5653 break;
5654 case TStreamerInfo::kObjectP: /* 64 */
5655 rel = new TStreamerObjectPointer(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5656 break;
5657 case TStreamerInfo::kTString: /* 65 */
5658 rel = new TStreamerObject(el->GetName(),el->GetTitle(),el->GetOffset(),el->GetTypeName());
5659 break;
5660 }
5661 if (rel) {
5662 (*fElements)[i] = rel;
5663 delete el;
5664 }
5665 }
5666 }
5667 }
5668 return;
5669 }
5670 //====process old versions before automatic schema evolution
5673 R__b >> fCheckSum;
5676 R__b >> fElements;
5677 R__b.CheckByteCount(R__s, R__c, TStreamerInfo::IsA());
5678 } else {
5679 R__c = R__b.WriteVersion(TStreamerInfo::IsA(), kTRUE);
5680 R__b.ClassBegin(TStreamerInfo::Class());
5681 R__b.ClassMember("TNamed");
5683 R__b.ClassMember("fCheckSum","UInt_t");
5684 R__b << fCheckSum;
5685 R__b.ClassMember("fClassVersion","Int_t");
5687
5688 //------------------------------------------------------------------------
5689 // Stream only non-artificial streamer elements
5690 //////////////////////////////////////////////////////////////////////////
5691
5692 R__b.ClassMember("fElements","TObjArray*");
5693 {
5694 TObjArray elements(fElements->GetEntriesFast());
5697 for (Int_t i = 0; i < nobjects; i++) {
5699 if (el != 0 && (el->IsA() == TStreamerArtificial::Class() || el->TestBit(TStreamerElement::kRepeat))) {
5700 // skip
5701 } else if (el != 0 && (el->TestBit(TStreamerElement::kCache) && !el->TestBit(TStreamerElement::kWrite))) {
5702 // skip
5703 } else if (el != 0) {
5704 elements.AddLast(el);
5705 }
5706 }
5707 R__b.WriteObjectAny(&elements, TObjArray::Class(), kFALSE);
5708 }
5709 R__b.ClassEnd(TStreamerInfo::Class());
5710 R__b.SetByteCount(R__c, kTRUE);
5711 }
5712}
5713
5714////////////////////////////////////////////////////////////////////////////////
5715/// Mark the classindex of the current file as using this TStreamerInfo.
5716/// This function is deprecated and its functionality is now done by
5717/// the overloads of TBuffer::TagStreamerInfo.
5718
5720{
5721 if (file) {
5722 // If the value of the atomic is kFALSE (equal to expected), change its value
5723 // to kTRUE and return true. Leave it as it is otherwise and return false.
5724 static std::atomic<Bool_t> onlyonce(kFALSE);
5725 Bool_t expected = kFALSE;
5726 if (onlyonce.compare_exchange_strong(expected,kTRUE)) {
5727 Warning("TagFile","This function is deprecated, use TBuffer::TagStreamerInfo instead");
5728 }
5729 TArrayC *cindex = file->GetClassIndex();
5730 Int_t nindex = cindex->GetSize();
5732 Error("TagFile","StreamerInfo: %s number: %d out of range[0,%d] in file: %s",
5733 GetName(),fNumber,nindex,file->GetName());
5734 return;
5735 }
5736 if (cindex->fArray[fNumber] == 0) {
5737 cindex->fArray[0] = 1;
5738 cindex->fArray[fNumber] = 1;
5739 }
5740 }
5741}
5742
5743////////////////////////////////////////////////////////////////////////////////
5744
5745#ifdef DOLOOP
5746#undef DOLOOP
5747#endif
5748#define DOLOOP for (k = 0, pointer = arr[0]; k < narr; pointer = arr[++k])
5749
5750namespace {
5751 static void PrintCR(int j,Int_t aleng, UInt_t ltype)
5752 {
5753 if (j == aleng-1) printf("\n");
5754 else {
5755 printf(", ");
5756 if (j%ltype == ltype-1) printf("\n ");
5757 }
5758 }
5759}
5760
5761////////////////////////////////////////////////////////////////////////////////
5762/// print value of element in object at pointer, type atype, leng aleng or *count
5763/// The function may be called in two ways:
5764/// -method1 len < 0
5765/// i is assumed to be the TStreamerElement number i in StreamerInfo
5766/// -method2 len >= 0
5767/// i is the type
5768/// address of variable is directly pointer.
5769/// len is the number of elements to be printed starting at pointer.
5770
5772{
5773 int j;
5774
5775 //assert(!((kOffsetP + kChar) <= atype && atype <= (kOffsetP + kBool) && count == 0));
5776 switch (atype) {
5777 // basic types
5778 case kBool: {Bool_t *val = (Bool_t* )ladd; printf("%d" ,*val); break;}
5779 case kChar: {Char_t *val = (Char_t* )ladd; printf("%d" ,*val); break;}
5780 case kShort: {Short_t *val = (Short_t* )ladd; printf("%d" ,*val); break;}
5781 case kInt: {Int_t *val = (Int_t* )ladd; printf("%d" ,*val); break;}
5782 case kLong: {Long_t *val = (Long_t* )ladd; printf("%ld",*val); break;}
5783 case kLong64: {Long64_t *val = (Long64_t* )ladd; printf("%lld",*val); break;}
5784 case kFloat: {Float_t *val = (Float_t* )ladd; printf("%f" ,*val); break;}
5785 case kFloat16: {Float_t *val = (Float_t* )ladd; printf("%f" ,*val); break;}
5786 case kDouble: {Double_t *val = (Double_t* )ladd; printf("%g" ,*val); break;}
5787 case kDouble32: {Double_t *val = (Double_t* )ladd; printf("%g" ,*val); break;}
5788 case kUChar: {UChar_t *val = (UChar_t* )ladd; printf("%u" ,*val); break;}
5789 case kUShort: {UShort_t *val = (UShort_t* )ladd; printf("%u" ,*val); break;}
5790 case kUInt: {UInt_t *val = (UInt_t* )ladd; printf("%u" ,*val); break;}
5791 case kULong: {ULong_t *val = (ULong_t* )ladd; printf("%lu",*val); break;}
5792 case kULong64: {ULong64_t *val = (ULong64_t*)ladd; printf("%llu",*val); break;}
5793 case kBits: {UInt_t *val = (UInt_t* )ladd; printf("%d" ,*val); break;}
5794
5795 // array of basic types array[8]
5796 case kOffsetL + kBool: {Bool_t *val = (Bool_t* )ladd; for(j=0;j<aleng;j++) { printf("%c " ,(char)val[j]); PrintCR(j,aleng,20); } break;}
5797 case kOffsetL + kChar: {Char_t *val = (Char_t* )ladd; for(j=0;j<aleng;j++) { printf("%c " ,val[j]); PrintCR(j,aleng,20); } break;}
5798 case kOffsetL + kShort: {Short_t *val = (Short_t* )ladd; for(j=0;j<aleng;j++) { printf("%d " ,val[j]); PrintCR(j,aleng,10); } break;}
5799 case kOffsetL + kInt: {Int_t *val = (Int_t* )ladd; for(j=0;j<aleng;j++) { printf("%d " ,val[j]); PrintCR(j,aleng,10); } break;}
5800 case kOffsetL + kLong: {Long_t *val = (Long_t* )ladd; for(j=0;j<aleng;j++) { printf("%ld ",val[j]); PrintCR(j,aleng, 5); } break;}
5801 case kOffsetL + kLong64: {Long64_t *val = (Long64_t* )ladd; for(j=0;j<aleng;j++) { printf("%lld ",val[j]);PrintCR(j,aleng, 5); } break;}
5802 case kOffsetL + kFloat: {Float_t *val = (Float_t* )ladd; for(j=0;j<aleng;j++) { printf("%f " ,val[j]); PrintCR(j,aleng, 5); } break;}
5803 case kOffsetL + kFloat16: {Float_t *val = (Float_t* )ladd; for(j=0;j<aleng;j++) { printf("%f " ,val[j]); PrintCR(j,aleng, 5); } break;}
5804 case kOffsetL + kDouble: {Double_t *val = (Double_t* )ladd; for(j=0;j<aleng;j++) { printf("%g " ,val[j]); PrintCR(j,aleng, 5); } break;}
5805 case kOffsetL + kDouble32:{Double_t *val = (Double_t* )ladd; for(j=0;j<aleng;j++) { printf("%g " ,val[j]); PrintCR(j,aleng, 5); } break;}
5806 case kOffsetL + kUChar: {UChar_t *val = (UChar_t* )ladd; for(j=0;j<aleng;j++) { printf("%u " ,val[j]); PrintCR(j,aleng,20); } break;}
5807 case kOffsetL + kUShort: {UShort_t *val = (UShort_t* )ladd; for(j=0;j<aleng;j++) { printf("%u " ,val[j]); PrintCR(j,aleng,10); } break;}
5808 case kOffsetL + kUInt: {UInt_t *val = (UInt_t* )ladd; for(j=0;j<aleng;j++) { printf("%u " ,val[j]); PrintCR(j,aleng, 5); } break;}
5809 case kOffsetL + kULong: {ULong_t *val = (ULong_t* )ladd; for(j=0;j<aleng;j++) { printf("%lu ",val[j]); PrintCR(j,aleng, 5); } break;}
5810 case kOffsetL + kULong64: {ULong64_t *val = (ULong64_t*)ladd; for(j=0;j<aleng;j++) { printf("%llu ",val[j]);PrintCR(j,aleng, 5); } break;}
5811 case kOffsetL + kBits: {UInt_t *val = (UInt_t* )ladd; for(j=0;j<aleng;j++) { printf("%d " ,val[j]); PrintCR(j,aleng, 5); } break;}
5812
5813 // pointer to an array of basic types array[n]
5814 case kOffsetP + kBool: {Bool_t **val = (Bool_t** )ladd; for(j=0;j<*count;j++) { printf("%d " ,(*val)[j]); PrintCR(j,aleng,20); } break;}
5815 case kOffsetP + kChar: {Char_t **val = (Char_t** )ladd; for(j=0;j<*count;j++) { printf("%d " ,(*val)[j]); PrintCR(j,aleng,20); } break;}
5816 case kOffsetP + kShort: {Short_t **val = (Short_t** )ladd; for(j=0;j<*count;j++) { printf("%d " ,(*val)[j]); PrintCR(j,aleng,10); } break;}
5817 case kOffsetP + kInt: {Int_t **val = (Int_t** )ladd; for(j=0;j<*count;j++) { printf("%d " ,(*val)[j]); PrintCR(j,aleng,10); } break;}
5818 case kOffsetP + kLong: {Long_t **val = (Long_t** )ladd; for(j=0;j<*count;j++) { printf("%ld ",(*val)[j]); PrintCR(j,aleng, 5); } break;}
5819 case kOffsetP + kLong64: {Long64_t **val = (Long64_t**)ladd; for(j=0;j<*count;j++) { printf("%lld ",(*val)[j]); PrintCR(j,aleng, 5); } break;}
5820 case kOffsetP + kFloat: {Float_t **val = (Float_t** )ladd; for(j=0;j<*count;j++) { printf("%f " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5821 case kOffsetP + kFloat16: {Float_t **val = (Float_t** )ladd; for(j=0;j<*count;j++) { printf("%f " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5822 case kOffsetP + kDouble: {Double_t **val = (Double_t**)ladd; for(j=0;j<*count;j++) { printf("%g " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5823 case kOffsetP + kDouble32:{Double_t **val = (Double_t**)ladd; for(j=0;j<*count;j++) { printf("%g " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5824 case kOffsetP + kUChar: {UChar_t **val = (UChar_t** )ladd; for(j=0;j<*count;j++) { printf("%u " ,(*val)[j]); PrintCR(j,aleng,20); } break;}
5825 case kOffsetP + kUShort: {UShort_t **val = (UShort_t**)ladd; for(j=0;j<*count;j++) { printf("%u " ,(*val)[j]); PrintCR(j,aleng,10); } break;}
5826 case kOffsetP + kUInt: {UInt_t **val = (UInt_t** )ladd; for(j=0;j<*count;j++) { printf("%u " ,(*val)[j]); PrintCR(j,aleng, 5); } break;}
5827 case kOffsetP + kULong: {ULong_t **val = (ULong_t** )ladd; for(j=0;j<*count;j++) { printf("%lu ",(*val)[j]); PrintCR(j,aleng, 5); } break;}
5828 case kOffsetP + kULong64: {ULong64_t**val = (ULong64_t**)ladd; for(j=0;j<*count;j++){ printf("%llu ",(*val)[j]); PrintCR(j,aleng, 5); } break;}
5829
5830 // array counter //[n]
5831 case kCounter: {Int_t *val = (Int_t*)ladd; printf("%d",*val); break;}
5832 // char *
5833 case kCharStar:{
5834 char **val = (char**)ladd;
5835 if (*val) printf("%s",*val);
5836 break;
5837 }
5838 // Class * derived from TObject with comment field //->
5839 case kObjectp: {
5840 TObject **obj = (TObject**)(ladd);
5842 printf("(%s*)%zx",el ? el->GetClass()->GetName() : "unknown_type",(size_t)(*obj));
5843 break;
5844 }
5845
5846 // Class* derived from TObject
5847 case kObjectP: {
5848 TObject **obj = (TObject**)(ladd);
5850 printf("(%s*)%zx",el ? el->GetClass()->GetName() : "unknown_type",(size_t)(*obj));
5851 break;
5852 }
5853
5854 // Class derived from TObject
5855 case kObject: {
5856 TObject *obj = (TObject*)(ladd);
5857 printf("%s",obj->GetName());
5858 break;
5859 }
5860
5861 // Special case for TString, TObject, TNamed
5862 case kTString: {
5863 TString *st = (TString*)(ladd);
5864 printf("%s",st->Data());
5865 break;
5866 }
5867 case kTObject: {
5868 TObject *obj = (TObject*)(ladd);
5869 printf("%s",obj->GetName());
5870 break;
5871 }
5872 case kTNamed: {
5873 TNamed *named = (TNamed*) (ladd);
5874 printf("%s/%s",named->GetName(),named->GetTitle());
5875 break;
5876 }
5877
5878 // Class * not derived from TObject with comment field //->
5879 case kAnyp: {
5880 TObject **obj = (TObject**)(ladd);
5882 printf("(%s*)0x%zx",el ? el->GetClass()->GetName() : "unknown_type",(size_t)(*obj));
5883 break;
5884 }
5885
5886 // Class* not derived from TObject
5887 case kAnyP: {
5888 TObject **obj = (TObject**)(ladd);
5890 printf("(%s*)0x%zx",el ? el->GetClass()->GetName() : "unknown_type",(size_t)(*obj));
5891 break;
5892 }
5893 // Any Class not derived from TObject
5894 case kOffsetL + kObjectp:
5895 case kOffsetL + kObjectP:
5896 case kAny: {
5897 printf("printing kAny case (%d)",atype);
5898// if (aElement) {
5899// TMemberStreamer *pstreamer = aElement->GetStreamer();
5900// if (pstreamer == 0) {
5901// //printf("ERROR, Streamer is null\n");
5902// //aElement->ls();
5903// break;
5904// }
5905// //(*pstreamer)(b,ladd,0);
5906// }
5907 break;
5908 }
5909 // Base Class
5910 case kBase: {
5911 printf("printing kBase case (%d)",atype);
5912 //aElement->ReadBuffer(b,pointer);
5913 break;
5914 }
5915
5916 case kOffsetL + kObject:
5917 case kOffsetL + kTString:
5918 case kOffsetL + kTObject:
5919 case kOffsetL + kTNamed:
5920 case kStreamer: {
5921 printf("printing kStreamer case (%d)",atype);
5922// TMemberStreamer *pstreamer = aElement->GetStreamer();
5923// if (pstreamer == 0) {
5924// //printf("ERROR, Streamer is null\n");
5925// //aElement->ls();
5926// break;
5927// }
5928// //UInt_t start,count;
5929// //b.ReadVersion(&start, &count);
5930// //(*pstreamer)(b,ladd,0);
5931// //b.CheckByteCount(start,count,IsA());
5932 break;
5933 }
5934
5935 case kStreamLoop: {
5936 printf("printing kStreamLoop case (%d)",atype);
5937// TMemberStreamer *pstreamer = aElement->GetStreamer();
5938// if (pstreamer == 0) {
5939// //printf("ERROR, Streamer is null\n");
5940// //aElement->ls();
5941// break;
5942// }
5943 //Int_t *counter = (Int_t*)(count);
5944 //UInt_t start,count;
5945 ///b.ReadVersion(&start, &count);
5946 //(*pstreamer)(b,ladd,*counter);
5947 //b.CheckByteCount(start,count,IsA());
5948 break;
5949 }
5950 case kSTL: {
5951 if (aElement) {
5952 static TClassRef stringClass("string");
5953 if (ladd && aElement->GetClass() == stringClass) {
5954 std::string *st = (std::string*)(ladd);
5955 printf("%s",st->c_str());
5956 } else {
5957 printf("(%s*)0x%zx",aElement->GetClass()->GetName(),(size_t)(ladd));
5958 }
5959 } else {
5960 printf("(unknown_type*)0x%zx",(size_t)(ladd));
5961 }
5962 break;
5963 }
5964 }
5965}
5966
5967////////////////////////////////////////////////////////////////////////////////
5968///function called by the TClass constructor when replacing an emulated class
5969///by the real class
5970
5972{
5975 while ((element = (TStreamerElement*)nextElement())) {
5976 element->Update(oldcl,newcl);
5977 }
5978 for (Int_t i=0;i < fNslots;i++) {
5979 fComp[i].Update(oldcl,newcl);
5980 }
5981}
5982
5983////////////////////////////////////////////////////////////////////////////////
5984/// Update the TClass pointer cached in this object.
5985
5987{
5988 if (fType != -1) {
5989 if (fClass == oldcl || strcmp(fClassName, newcl->GetName()) == 0)
5990 fClass = newcl;
5991 else if (fClass == 0 && TClassTable::GetDict(fClassName))
5993 }
5994}
5995
5996////////////////////////////////////////////////////////////////////////////////
5997/// Generate emulated collection proxy for a given class.
5998
6004
6005////////////////////////////////////////////////////////////////////////////////
6006/// Generate emulated class streamer for a given collection class.
6007
6013
6014////////////////////////////////////////////////////////////////////////////////
6015/// Generate proxy from static functions.
6016
6018TStreamerInfo::GenExplicitProxy( const ::ROOT::TCollectionProxyInfo &info, TClass *cl )
6019{
6021}
6022
6023////////////////////////////////////////////////////////////////////////////////
6024/// Generate class streamer from static functions.
6025
6027TStreamerInfo::GenExplicitClassStreamer( const ::ROOT::TCollectionProxyInfo &info, TClass *cl )
6028{
6030}
6031
6032//
6033// Utility functions
6034//
6035static TStreamerElement *
6036R__CreateEmulatedElement(const char *dmName, const std::string &dmFull, Int_t offset, bool silent, bool needAlign)
6037{
6038 // Create a TStreamerElement for the type 'dmFull' and whose data member name is 'dmName'.
6039
6040 TString s1( TClassEdit::ShortType(dmFull.c_str(),0) );
6042 Bool_t dmIsPtr = (s1 != dmType);
6043 const char *dmTitle = "Emulation";
6044 // Over align the basic data types.
6045 size_t align = alignof(std::max_align_t);
6046 if (needAlign && offset % align != 0)
6047 offset = (Int_t)AlignUp((size_t)offset, align);
6048
6049 TDataType *dt = gROOT->GetType(dmType);
6050 if (dt && dt->GetType() > 0 ) { // found a basic type
6052 dtype = dt->GetType();
6053 dsize = dt->Size();
6054 // Use the precise alignment for the basic type if available.
6055 if (needAlign && dt->GetAlignOf()) {
6056 align = dt->GetAlignOf();
6057 if (offset % align != 0)
6058 offset = (Int_t)AlignUp((size_t)offset, align);
6059 }
6060 if (dmIsPtr && dtype != kCharStar) {
6061 if (!silent)
6062 Error("Pair Emulation Building","%s is not yet supported in pair emulation",
6063 dmFull.c_str());
6064 return 0;
6065 } else {
6067 el->SetSize(dsize);
6068 return el;
6069 }
6070 } else {
6071
6072 static const char *full_string_name = "basic_string<char,char_traits<char>,allocator<char> >";
6073 if (strcmp(dmType,"string") == 0 || strcmp(dmType,"std::string") == 0 || strcmp(dmType,full_string_name)==0 ) {
6075 }
6077 return new TStreamerSTL(dmName,dmTitle,offset,dmFull.c_str(),dmFull.c_str(),dmIsPtr);
6078 }
6080 if (!clm) {
6082 if (enumdesc) {
6083 auto dtype = enumdesc->GetUnderlyingType();
6084 auto el = new TStreamerBasicType(dmName, dmTitle, offset, dtype, dmFull.c_str());
6086 if (datatype)
6087 el->SetSize(datatype->Size());
6088 else
6089 el->SetSize(sizeof(int)); // Default size of enums.
6090 return el;
6091 }
6092 return nullptr;
6093 }
6094 if (clm->GetState() <= TClass::kForwardDeclared)
6095 return nullptr;
6096 // a pointer to a class
6097 if ( dmIsPtr ) {
6098 if (clm->IsTObject()) {
6100 } else {
6102 }
6103 }
6104 // a class
6105 assert(ROOT::Internal::IsValidAlignment(clm->GetClassAlignment()));
6106 align = std::max(align, clm->GetClassAlignment());
6107 if (needAlign && ((offset % align) != 0))
6108 offset = (Int_t)AlignUp((size_t)offset, align);
6109 if (clm->IsTObject()) {
6110 return new TStreamerObject(dmName,dmTitle,offset,dmFull.c_str());
6111 } else if(clm == TString::Class() && !dmIsPtr) {
6113 } else {
6114 return new TStreamerObjectAny(dmName,dmTitle,offset,dmFull.c_str());
6115 }
6116 }
6117}
6118
6119/// \brief Generate the TClass and TStreamerInfo for the requested pair.
6120/// This creates a TVirtualStreamerInfo for the pair and trigger the BuildCheck/Old to
6121/// provoke the creation of the corresponding TClass. This relies on the dictionary for
6122/// std::pair<const int, int> to already exist (or the interpreter information being available)
6123/// as it is used as a template.
6124/// \note The returned object is owned by the caller.
6126{
6127 // Generate a TStreamerInfo for a std::pair<fname,sname>
6128 // This TStreamerInfo is then used as if it was read from a file to generate
6129 // and emulated TClass.
6130
6132 const char *msg = "problematic";
6134 msg = "the same";
6135 else if (hint_pair_offset > hint_pair_size) {
6136 if (hint_pair_size == 0)
6137 msg = "not specified";
6138 else
6139 msg = "smaller";
6140 }
6141 Error("GenerateInfoForPair",
6142 "Called with inconsistent offset and size. For \"std::pair<%s,%s>\" the requested offset is %ld but the size is %s (%ld)",
6143 firstname.c_str(), secondname.c_str(), (long)hint_pair_offset, msg, (long)hint_pair_offset);
6144 return nullptr;
6145 }
6146 TStreamerInfo *i = (TStreamerInfo*)TClass::GetClass("pair<const int,int>")->GetStreamerInfo()->Clone();
6147 std::string pname = "pair<" + firstname + "," + secondname;
6148 pname += (pname[pname.length()-1]=='>') ? " >" : ">";
6149 i->SetName(pname.c_str());
6150 i->SetClass(nullptr);
6151 i->GetElements()->Delete();
6152 TStreamerElement *fel = R__CreateEmulatedElement("first", firstname, 0, silent, /*needAlign=*/false);
6153 Int_t size = 0;
6154 if (fel) {
6155 i->GetElements()->Add(fel);
6156 i->fAlignment = std::max(i->fAlignment, fel->GetAlignment());
6157 } else {
6158 delete i;
6159 return 0;
6160 }
6161 if (hint_pair_offset)
6163 TStreamerElement *second =
6164 R__CreateEmulatedElement("second", secondname, size, silent, /*needAlign=*/!hint_pair_offset);
6165 if (second) {
6166 i->GetElements()->Add(second);
6167 i->fAlignment = std::max(i->fAlignment, second->GetAlignment());
6168 } else {
6169 delete i;
6170 return 0;
6171 }
6173 // Hide the warning about the missing pair dictionary.
6175 i->BuildCheck(nullptr, kFALSE); // Skipping the loading part (it would leads to infinite recursion on this very routine)
6177 if (i->TestBit(kCanDelete)) {
6178 // The StreamerInfo was deemed to be a duplicated (most likely case is
6179 // that we have the interpreter information already loaded for the
6180 // pair), so we need to delete it and return the one we already have.
6181 auto cl = i->GetClass();
6182 delete i;
6183 return cl->GetStreamerInfo();
6184 }
6185
6186 // In the state emulated, BuildOld would recalculate the offset and undo the offset update.
6187 // Note: we should consider adding a new state just for this (the hints indicates that we are mapping a compiled class but
6188 // then we would have to investigate all use of the state with <= and >= condition to make sure they are still appropriate).
6189 if (hint_pair_size) {
6192 }
6193
6194 i->BuildOld();
6195
6196 if (hint_pair_size)
6198 return i;
6199}
6200
6202{
6203 const static int pairlen = std::char_traits<char>::length("pair<");
6204 if (pairclassname.compare(0, pairlen, "pair<") != 0) {
6205 if (!silent)
6206 Error("GenerateInfoForPair", "The class name passed is not a pair: %s", pairclassname.c_str());
6207 return nullptr;
6208 }
6209
6210 std::vector<std::string> inside;
6211 int nested = 0;
6212 int num = TClassEdit::GetSplit(pairclassname.c_str(), inside, nested);
6213 if (num != 4) {
6214 if (!silent)
6215 Error("GenerateInfoForPair", "Could not find the pair arguments in %s", pairclassname.c_str());
6216 return nullptr;
6217 }
6218
6219 return GenerateInfoForPair(inside[1], inside[2], silent, hint_pair_offset, hint_pair_size);
6220}
#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:77
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:59
short Version_t
Class version identifier (short)
Definition RtypesCore.h:79
char Char_t
Character 1 byte (char)
Definition RtypesCore.h:51
unsigned long ULong_t
Unsigned long integer 4 bytes (unsigned long). Size depends on architecture.
Definition RtypesCore.h:69
long Long_t
Signed long integer 4 bytes (long). Size depends on architecture.
Definition RtypesCore.h:68
unsigned int UInt_t
Unsigned integer 4 bytes (unsigned int)
Definition RtypesCore.h:60
float Float_t
Float 4 bytes (float)
Definition RtypesCore.h:71
short Short_t
Signed Short integer 2 bytes (short)
Definition RtypesCore.h:53
constexpr Bool_t kFALSE
Definition RtypesCore.h:108
double Double_t
Double 8 bytes.
Definition RtypesCore.h:73
long double LongDouble_t
Long Double (not portable)
Definition RtypesCore.h:75
long long Long64_t
Portable signed long integer 8 bytes.
Definition RtypesCore.h:83
constexpr Bool_t kTRUE
Definition RtypesCore.h:107
const char Option_t
Option string (const char)
Definition RtypesCore.h:80
const Bool_t kIterBackward
Definition TCollection.h:43
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
EDataType
Definition TDataType.h:28
@ kNoType_t
Definition TDataType.h:33
@ kFloat_t
Definition TDataType.h:31
@ kULong64_t
Definition TDataType.h:32
@ kInt_t
Definition TDataType.h:30
@ kLong_t
Definition TDataType.h:30
@ kDouble32_t
Definition TDataType.h:31
@ kShort_t
Definition TDataType.h:29
@ kBool_t
Definition TDataType.h:32
@ kULong_t
Definition TDataType.h:30
@ kLong64_t
Definition TDataType.h:32
@ kUShort_t
Definition TDataType.h:29
@ kDouble_t
Definition TDataType.h:31
@ kCharStar
Definition TDataType.h:34
@ kChar_t
Definition TDataType.h:29
@ kUChar_t
Definition TDataType.h:29
@ kUInt_t
Definition TDataType.h:30
@ kFloat16_t
Definition TDataType.h:33
@ kOther_t
Definition TDataType.h:32
Bool_t operator!=(const TDatime &d1, const TDatime &d2)
Definition TDatime.h:104
@ kIsUnionMember
Definition TDictionary.h:74
@ kIsAbstract
Definition TDictionary.h:71
@ kIsStatic
Definition TDictionary.h:80
const Int_t kMaxLen
#define gDirectory
Definition TDirectory.h:385
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
constexpr Int_t kError
Definition TError.h:47
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:148
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:783
#define gROOT
Definition TROOT.h:426
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:2509
R__EXTERN TSystem * gSystem
Definition TSystem.h:582
#define R__LOCKGUARD(mutex)
#define snprintf
Definition civetweb.c:1579
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:6616
Bool_t IsSyntheticPair() const
Definition TClass.h:537
TDataMember * GetDataMember(const char *datamember) const
Return pointer to datamember object with name "datamember".
Definition TClass.cxx:3501
EState GetState() const
Definition TClass.h:504
ROOT::ESTLType GetCollectionType() const
Return the 'type' of the STL the TClass is representing.
Definition TClass.cxx:2907
void RemoveStreamerInfo(Int_t slot)
Remove and delete the StreamerInfo in the given slot.
Definition TClass.cxx:7477
Bool_t HasDataMemberInfo() const
Definition TClass.h:420
void CopyCollectionProxy(const TVirtualCollectionProxy &)
Replaces the collection proxy for this class.
Definition TClass.cxx:2477
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:7453
TVirtualStreamerInfo * GetCurrentStreamerInfo()
Definition TClass.h:454
size_t GetClassAlignment() const
Return the alignment requirement (in bytes) for objects of this class.
Definition TClass.cxx:5781
void IgnoreTObjectStreamer(Bool_t ignore=kTRUE)
When the class kIgnoreTObjectStreamer bit is set, the automatically generated Streamer will not call ...
Definition TClass.cxx:4899
TClass * GetBaseClass(const char *classname)
Return pointer to the base class "classname".
Definition TClass.cxx:2662
Longptr_t GetDataMemberOffset(const char *membername) const
return offset for member name.
Definition TClass.cxx:3539
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:6605
Bool_t HasInterpreterInfo() const
Definition TClass.h:424
void BuildRealData(void *pointer=nullptr, Bool_t isTransient=kFALSE)
Build a full list of persistent data members.
Definition TClass.cxx:2038
TList * GetListOfDataMembers(Bool_t load=kTRUE)
Return list containing the TDataMembers of a class.
Definition TClass.cxx:3828
TList * GetListOfRealData() const
Definition TClass.h:468
Int_t Size() const
Return size of object of this class.
Definition TClass.cxx:5806
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:1934
TList * GetListOfBases()
Return list containing the TBaseClass(es) of a class.
Definition TClass.cxx:3694
const TObjArray * GetStreamerInfos() const
Definition TClass.h:508
Bool_t IsLoaded() const
Return true if the shared library of this class is currently in the a process's memory.
Definition TClass.cxx:6017
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition TClass.cxx:6043
Bool_t IsForeign() const
Return kTRUE is the class is Foreign (the class does not have a Streamer method).
Definition TClass.cxx:6052
TVirtualStreamerInfo * GetStreamerInfo(Int_t version=0, Bool_t isTransient=kFALSE) const
returns a pointer to the TVirtualStreamerInfo object for version If the object does not exist,...
Definition TClass.cxx:4657
ECheckSum
Definition TClass.h:111
@ kLatestCheckSum
Definition TClass.h:120
@ kNoRange
Definition TClass.h:115
@ kCurrentCheckSum
Definition TClass.h:112
@ kNoBaseCheckSum
Definition TClass.h:119
@ kReflex
Definition TClass.h:117
@ kReflexNoComment
Definition TClass.h:114
@ kWithTypeDef
Definition TClass.h:116
@ kNoRangeCheck
Definition TClass.h:118
@ kNoEnum
Definition TClass.h:113
Int_t GetBaseClassOffset(const TClass *toBase, void *address=nullptr, bool isDerivedObject=true)
Definition TClass.cxx:2812
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition TClass.cxx:2918
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:6191
@ kInterpreted
Definition TClass.h:129
@ kEmulated
Definition TClass.h:128
@ kNoInfo
Definition TClass.h:125
@ kForwardDeclared
Definition TClass.h:127
Bool_t IsVersioned() const
Definition TClass.h:538
void SetClassSize(Int_t sizof)
Definition TClass.h:316
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:3565
@ kWarned
Definition TClass.h:107
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition TClass.cxx:2994
An array of clone (identical) objects.
static TClass * Class()
static TVirtualCollectionProxy * GenEmulatedProxy(const char *class_name, Bool_t silent)
Generate emulated collection proxy for a given class.
static TClassStreamer * GenEmulatedClassStreamer(const char *class_name, Bool_t silent)
Generate emulated class streamer for a given collection class.
static Proxy_t * GenExplicitProxy(const ::ROOT::TCollectionProxyInfo &info, TClass *cl)
Generate proxy from static functions.
static TClassStreamer * GenExplicitClassStreamer(const ::ROOT::TCollectionProxyInfo &info, TClass *cl)
Generate class streamer from static functions.
virtual Int_t GetEntries() const
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:1377
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:459
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:1081
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:885
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1095
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition TObject.cxx:1123
virtual void ls(Option_t *option="") const
The ls function lists the contents of a class on stdout.
Definition TObject.cxx:595
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:1069
void Obsolete(const char *method, const char *asOfVers, const char *removedFromVers) const
Use this method to declare a method obsolete.
Definition TObject.cxx:1166
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:138
void ToLower()
Change string to lower-case.
Definition TString.cxx:1189
void Clear()
Clear string without changing its capacity.
Definition TString.cxx:1241
const char * Data() const
Definition TString.h:384
@ kTrailing
Definition TString.h:284
TString & Append(const char *cs)
Definition TString.h:581
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
Definition TString.cxx:2384
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition TString.cxx:2362
static TClass * Class()
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:641
virtual const char * BaseName(const char *pathname)
Base name of a file name. Base name of /user/root is root.
Definition TSystem.cxx:944
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.
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.
@ 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>