Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TStreamerInfoActions.cxx
Go to the documentation of this file.
1 // @(#)root/io:$Id$
2 // Author: Philippe Canal 05/2010
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 #include "TStreamerInfo.h"
13 #include "TStreamerInfoActions.h"
14 #include "TROOT.h"
15 #include "TStreamerElement.h"
16 #include "TVirtualMutex.h"
17 #include "TInterpreter.h"
18 #include "TError.h"
19 #include "TVirtualArray.h"
20 #include "TBufferFile.h"
21 #include "TBufferText.h"
22 #include "TMemberStreamer.h"
23 #include "TError.h"
24 #include "TClassEdit.h"
26 #include "TProcessID.h"
27 #include "TFile.h"
28 
29 static const Int_t kRegrouped = TStreamerInfo::kOffsetL;
30 
31 // More possible optimizations:
32 // Avoid call the virtual version of TBuffer::ReadInt and co.
33 // Merge the Reading of the version and the looking up or the StreamerInfo
34 // Avoid if (bytecnt) inside the CheckByteCount routines and avoid multiple (mostly useless nested calls)
35 // Try to avoid if statement on onfile class being set (TBufferFile::ReadClassBuffer).
36 
37 using namespace TStreamerInfoActions;
38 
39 #ifdef _AIX
40 # define INLINE_TEMPLATE_ARGS
41 #else
42 # define INLINE_TEMPLATE_ARGS inline
43 #endif
44 
45 
46 namespace TStreamerInfoActions
47 {
48  bool IsDefaultVector(TVirtualCollectionProxy &proxy)
49  {
50  const auto props = proxy.GetProperties();
51  const bool isVector = proxy.GetCollectionType() == ROOT::kSTLvector;
52  const bool hasDefaultAlloc = !(props & TVirtualCollectionProxy::kCustomAlloc);
53  const bool isEmulated = props & TVirtualCollectionProxy::kIsEmulated;
54 
55  return isEmulated || (isVector && hasDefaultAlloc);
56  }
57 
58  template <typename From>
59  struct WithFactorMarker {
60  typedef From Value_t;
61  };
62 
63  template <typename From>
64  struct NoFactorMarker {
65  typedef From Value_t;
66  };
67 
68  struct BitsMarker {
69  typedef UInt_t Value_t;
70  };
71 
72  void TConfiguration::AddToOffset(Int_t delta)
73  {
74  // Add the (potentially negative) delta to all the configuration's offset. This is used by
75  // TBranchElement in the case of split sub-object.
76 
77  if (fOffset != TVirtualStreamerInfo::kMissing)
78  fOffset += delta;
79  }
80 
81  void TConfiguration::SetMissing()
82  {
83  // Add the (potentially negative) delta to all the configuration's offset. This is used by
84  // TBranchElement in the case of split sub-object.
85 
86  fOffset = TVirtualStreamerInfo::kMissing;
87  }
88 
89  void TConfiguredAction::PrintDebug(TBuffer &buf, void *addr) const
90  {
91  // Inform the user what we are about to stream.
92 
93  // Idea, we should find a way to print the name of the function
94  if (fConfiguration) fConfiguration->PrintDebug(buf,addr);
95  }
96 
97  void TConfiguration::Print() const
98  {
99  // Inform the user what we are about to stream.
100 
101  TStreamerInfo *info = (TStreamerInfo*)fInfo;
102  TStreamerElement *aElement = fCompInfo->fElem;
103  TString sequenceType;
104  aElement->GetSequenceType(sequenceType);
105 
106  printf("StreamerInfoAction, class:%s, name=%s, fType[%d]=%d,"
107  " %s, offset=%d (%s)\n",
108  info->GetClass()->GetName(), aElement->GetName(), fElemId, fCompInfo->fType,
109  aElement->ClassName(), fOffset, sequenceType.Data());
110  }
111 
112  void TConfiguration::PrintDebug(TBuffer &buf, void *addr) const
113  {
114  // Inform the user what we are about to stream.
115 
116  if (gDebug > 1) {
117  // Idea: We should print the name of the action function.
118  TStreamerInfo *info = (TStreamerInfo*)fInfo;
119  TStreamerElement *aElement = fCompInfo->fElem;
120  TString sequenceType;
121  aElement->GetSequenceType(sequenceType);
122 
123  printf("StreamerInfoAction, class:%s, name=%s, fType[%d]=%d,"
124  " %s, bufpos=%d, arr=%p, offset=%d (%s)\n",
125  info->GetClass()->GetName(), aElement->GetName(), fElemId, fCompInfo->fType,
126  aElement->ClassName(), buf.Length(), addr, fOffset, sequenceType.Data());
127  }
128  }
129 
130  void TLoopConfiguration::Print() const
131  {
132  // Inform the user what we are about to stream.
133 
134  printf("TLoopConfiguration: unconfigured\n");
135  }
136 
137 
138  struct TGenericConfiguration : TConfiguration {
139  // Configuration of action using the legacy code.
140  // Mostly to cancel out the PrintDebug.
141  public:
142  TGenericConfiguration(TVirtualStreamerInfo *info, UInt_t id, TCompInfo_t *compinfo, Int_t offset = 0) : TConfiguration(info,id,compinfo,offset) {};
143  void PrintDebug(TBuffer &, void *) const {
144  // Since we call the old code, it will print the debug statement.
145  }
146 
147  virtual TConfiguration *Copy() { return new TGenericConfiguration(*this); }
148  };
149 
150  struct TBitsConfiguration : TConfiguration {
151  // Configuration of action handling kBits.
152  // In this case we need to know both the location
153  // of the member (fBits) and the start of the object
154  // (its TObject part to be exact).
155 
156  Int_t fObjectOffset; // Offset of the TObject part within the object
157 
158  TBitsConfiguration(TVirtualStreamerInfo *info, UInt_t id, TCompInfo_t *compinfo, Int_t offset = 0) : TConfiguration(info,id,compinfo,offset),fObjectOffset(0) {};
159  void PrintDebug(TBuffer &, void *) const {
160  TStreamerInfo *info = (TStreamerInfo*)fInfo;
161  TStreamerElement *aElement = fCompInfo->fElem;
162  TString sequenceType;
163  aElement->GetSequenceType(sequenceType);
164 
165  printf("StreamerInfoAction, class:%s, name=%s, fType[%d]=%d,"
166  " %s, offset=%d (%s)\n",
167  info->GetClass()->GetName(), aElement->GetName(), fElemId, fCompInfo->fType,
168  aElement->ClassName(), fOffset, sequenceType.Data());
169  }
170 
171  void AddToOffset(Int_t delta)
172  {
173  // Add the (potentially negative) delta to all the configuration's offset. This is used by
174  // TBranchElement in the case of split sub-object.
175 
176  if (fOffset != TVirtualStreamerInfo::kMissing)
177  fOffset += delta;
178  fObjectOffset = 0;
179  }
180 
181  void SetMissing()
182  {
183  fOffset = TVirtualStreamerInfo::kMissing;
184  fObjectOffset = 0;
185  }
186 
187  virtual TConfiguration *Copy() { return new TBitsConfiguration(*this); }
188 
189  };
190 
191  Int_t GenericReadAction(TBuffer &buf, void *addr, const TConfiguration *config)
192  {
193  char *obj = (char*)addr;
194  TGenericConfiguration *conf = (TGenericConfiguration*)config;
195  return ((TStreamerInfo*)conf->fInfo)->ReadBuffer(buf, &obj, &(conf->fCompInfo), /*first*/ 0, /*last*/ 1, /*narr*/ 1, config->fOffset, 2);
196  }
197 
198  Int_t GenericWriteAction(TBuffer &buf, void *addr, const TConfiguration *config)
199  {
200  char *obj = (char*)addr;
201  TGenericConfiguration *conf = (TGenericConfiguration*)config;
202  return ((TStreamerInfo*)conf->fInfo)->WriteBufferAux(buf, &obj, &(conf->fCompInfo), /*first*/ 0, /*last*/ 1, /*narr*/ 1, config->fOffset, 2);
203  }
204 
205  template <typename T>
206  INLINE_TEMPLATE_ARGS Int_t ReadBasicType(TBuffer &buf, void *addr, const TConfiguration *config)
207  {
208  T *x = (T*)( ((char*)addr) + config->fOffset );
209  // Idea: Implement buf.ReadBasic/Primitive to avoid the return value
210  buf >> *x;
211  return 0;
212  }
213 
214  void HandleReferencedTObject(TBuffer &buf, void *addr, const TConfiguration *config) {
215  TBitsConfiguration *conf = (TBitsConfiguration*)config;
216  UShort_t pidf;
217  buf >> pidf;
218  pidf += buf.GetPidOffset();
219  TProcessID *pid = buf.ReadProcessID(pidf);
220  if (pid!=0) {
221  TObject *obj = (TObject*)( ((char*)addr) + conf->fObjectOffset);
222  UInt_t gpid = pid->GetUniqueID();
223  UInt_t uid;
224  if (gpid>=0xff) {
225  uid = obj->GetUniqueID() | 0xff000000;
226  } else {
227  uid = ( obj->GetUniqueID() & 0xffffff) + (gpid<<24);
228  }
229  obj->SetUniqueID(uid);
230  pid->PutObjectWithID(obj);
231  }
232  }
233 
234  template <>
235  INLINE_TEMPLATE_ARGS Int_t ReadBasicType<BitsMarker>(TBuffer &buf, void *addr, const TConfiguration *config)
236  {
237  UInt_t *x = (UInt_t*)( ((char*)addr) + config->fOffset );
238  // Idea: Implement buf.ReadBasic/Primitive to avoid the return value
239  // Idea: This code really belongs inside TBuffer[File]
240  buf >> *x;
241 
242  if ((*x & kIsReferenced) != 0) {
243  HandleReferencedTObject(buf,addr,config);
244  }
245  return 0;
246  }
247 
248  template <typename T>
249  INLINE_TEMPLATE_ARGS Int_t WriteBasicType(TBuffer &buf, void *addr, const TConfiguration *config)
250  {
251  T *x = (T *)(((char *)addr) + config->fOffset);
252  // Idea: Implement buf.ReadBasic/Primitive to avoid the return value
253  buf << *x;
254  return 0;
255  }
256 
257  INLINE_TEMPLATE_ARGS Int_t WriteTextTNamed(TBuffer &buf, void *addr, const TConfiguration *config)
258  {
259  void *x = (void *)(((char *)addr) + config->fOffset);
260  // Idea: Implement buf.ReadBasic/Primitive to avoid the return value
261  buf.StreamObject(x, TNamed::Class(), TNamed::Class());
262  return 0;
263  }
264 
265  INLINE_TEMPLATE_ARGS Int_t WriteTextTObject(TBuffer &buf, void *addr, const TConfiguration *config)
266  {
267  void *x = (void *)(((char *)addr) + config->fOffset);
268  // Idea: Implement buf.ReadBasic/Primitive to avoid the return value
269  buf.StreamObject(x, TObject::Class(), TObject::Class());
270  return 0;
271  }
272 
273  INLINE_TEMPLATE_ARGS Int_t WriteTextBaseClass(TBuffer &buf, void *addr, const TConfiguration *config)
274  {
275  void *x = (void *)(((char *)addr) + config->fOffset);
276  // Idea: Implement buf.ReadBasic/Primitive to avoid the return value
277  ((TBufferText *)&buf)->WriteBaseClass(x, (TStreamerBase *)config->fCompInfo->fElem);
278  return 0;
279  }
280 
281  INLINE_TEMPLATE_ARGS Int_t WriteTextStreamer(TBuffer &buf, void *addr, const TConfiguration *config)
282  {
283  void *x = (void *)(((char *)addr) + config->fOffset);
284  TMemberStreamer *pstreamer = config->fCompInfo->fStreamer;
285  UInt_t pos = buf.WriteVersion(config->fInfo->IsA(), kTRUE);
286  (*pstreamer)(buf, x, config->fCompInfo->fLength);
287  buf.SetByteCount(pos, kTRUE);
288  return 0;
289  }
290 
291  INLINE_TEMPLATE_ARGS Int_t ReadTextObject(TBuffer &buf, void *addr, const TConfiguration *config)
292  {
293  void *x = (void *)(((char *)addr) + config->fOffset);
294  buf.ReadFastArray(x, config->fCompInfo->fClass, config->fCompInfo->fLength, config->fCompInfo->fStreamer);
295  return 0;
296  }
297 
298  INLINE_TEMPLATE_ARGS Int_t ReadTextTObject(TBuffer &buf, void *addr, const TConfiguration *config)
299  {
300  void *x = (void *)(((char *)addr) + config->fOffset);
301  buf.StreamObject(x, TObject::Class(), TObject::Class());
302  return 0;
303  }
304 
305  INLINE_TEMPLATE_ARGS Int_t ReadTextBaseClass(TBuffer &buf, void *addr, const TConfiguration *config)
306  {
307  void *x = (void *)(((char *)addr) + config->fOffset);
308  // Idea: Implement buf.ReadBasic/Primitive to avoid the return value
309  ((TBufferText *)&buf)->ReadBaseClass(x, (TStreamerBase *)config->fCompInfo->fElem);
310  return 0;
311  }
312 
313  INLINE_TEMPLATE_ARGS Int_t ReadTextStreamer(TBuffer &buf, void *addr, const TConfiguration *config)
314  {
315  void *x = (void *)(((char *)addr) + config->fOffset);
316  TMemberStreamer *pstreamer = config->fCompInfo->fStreamer;
317 
318  UInt_t start, count;
319  /* Version_t v = */ buf.ReadVersion(&start, &count, config->fCompInfo->fClass);
320  (*pstreamer)(buf, x, config->fCompInfo->fLength);
321  buf.CheckByteCount(start, count, config->fCompInfo->fElem->GetFullName());
322  return 0;
323  }
324 
325  INLINE_TEMPLATE_ARGS Int_t ReadTextTObjectBase(TBuffer &buf, void *addr, const TConfiguration *config)
326  {
327  // action required to call custom code for TObject as base class
328  void *x = (void *)(((char *)addr) + config->fOffset);
329  buf.ReadClassBuffer(TObject::Class(), x, TObject::Class());
330  return 0;
331  }
332 
333  INLINE_TEMPLATE_ARGS Int_t ReadTextTNamed(TBuffer &buf, void *addr, const TConfiguration *config)
334  {
335  void *x = (void *)(((char *)addr) + config->fOffset);
336  buf.StreamObject(x, TNamed::Class(), TNamed::Class());
337  return 0;
338  }
339 
340  /** Direct copy of code from TStreamerInfo::WriteBufferAux,
341  * potentially can be used later for non-text streaming */
342  template<bool kIsTextT>
343  INLINE_TEMPLATE_ARGS Int_t WriteSTLp(TBuffer &buf, void *addr, const TConfiguration *config)
344  {
345  TClass *cl = config->fCompInfo->fClass;
346  TMemberStreamer *pstreamer = config->fCompInfo->fStreamer;
347  TVirtualCollectionProxy *proxy = cl->GetCollectionProxy();
348  TClass* vClass = proxy ? proxy->GetValueClass() : 0;
349  UInt_t eoffset = 0; // extra parameter of TStreamerInfo::WriteBufferAux, 0 for all kind of objects writing
350  UInt_t ioffset = eoffset + config->fOffset;
351 
352  if (!buf.TestBit(TBuffer::kCannotHandleMemberWiseStreaming)
353  && proxy && vClass
354  && config->fInfo->GetStreamMemberWise()
355  && cl->CanSplit()
356  && !(strspn(config->fCompInfo->fElem->GetTitle(),"||") == 2)
357  && !(vClass->TestBit(TClass::kHasCustomStreamerMember)) ) {
358  // Let's save the collection member-wise.
359 
360  UInt_t pos = buf.WriteVersionMemberWise(config->fInfo->IsA(),kTRUE);
361  buf.WriteVersion( vClass, kFALSE );
362 
363  // TODO: subinfo used for WriteBufferSTL call, which is private for the moment
364  //TStreamerInfo *subinfo = (TStreamerInfo*)vClass->GetStreamerInfo();
365 
366  //for (int k = 0; k < narr; ++k) {
367  char **contp = (char **)((char *)addr + ioffset);
368  for(int j=0;j<config->fCompInfo->fLength;++j) {
369  char *cont = contp[j];
370  TVirtualCollectionProxy::TPushPop helper( proxy, cont );
371  Int_t nobjects = cont ? proxy->Size() : 0;
372  buf << nobjects;
373 
374  // TODO: method is private, should be made accesible from here
375  // subinfo->WriteBufferSTL(buf,proxy,nobjects);
376  }
377  //}
378  buf.SetByteCount(pos,kTRUE);
379  return 0;
380  }
381  UInt_t pos = buf.WriteVersion(config->fInfo->IsA(), kTRUE);
382  if (kIsTextT) {
383  // use same method which is used in kSTL
384  buf.WriteFastArray((void **)((char *)addr + ioffset), cl, config->fCompInfo->fLength, kFALSE, pstreamer);
385  } else if (pstreamer == nullptr) {
386  // for (int k = 0; k < narr; ++k) {
387  char **contp = (char **)((char *)addr + ioffset);
388  for (int j = 0; j < config->fCompInfo->fLength; ++j) {
389  char *cont = contp[j];
390  cl->Streamer(cont, buf);
391  }
392  // }
393  } else {
394  // for (int k = 0; k < narr; ++k) {
395  (*pstreamer)(buf, (char *)addr + ioffset, config->fCompInfo->fLength);
396  //}
397  }
398  buf.SetByteCount(pos, kTRUE);
399  return 0;
400  }
401 
402 
403  /** Direct copy of code from TStreamerInfo::WriteBufferAux,
404  * potentially can be used later for non-text streaming */
405  template<bool kIsTextT>
406  INLINE_TEMPLATE_ARGS Int_t ReadSTLp(TBuffer &buf, void *addr, const TConfiguration *config)
407  {
408  TClass *cle = config->fCompInfo->fClass;
409  TStreamerElement * aElement = (TStreamerElement*) config->fCompInfo->fElem;
410  TMemberStreamer *pstreamer = config->fCompInfo->fStreamer;
411  //TVirtualCollectionProxy *proxy = cl->GetCollectionProxy();
412  //TClass* vClass = proxy ? proxy->GetValueClass() : 0;
413 
414  UInt_t eoffset = 0; // extra parameter of TStreamerInfo::WriteBufferAux, 0 for all kind of objects writing
415  UInt_t ioffset = eoffset + config->fOffset;
416 
417 
418  UInt_t start,count;
419  Version_t vers = buf.ReadVersion(&start, &count, cle);
420 
421  if (!kIsTextT && (vers & TBufferFile::kStreamedMemberWise) ) {
422  // Collection was saved member-wise
423 
424  vers &= ~( TBufferFile::kStreamedMemberWise );
425 
426  TClass *newClass = aElement->GetNewClass();
427  TClass *oldClass = aElement->GetClassPointer();
428  if( vers < 9 && newClass && newClass!=oldClass ) {
429  Error( "ReadBuffer", "Unfortunately, version %d of TStreamerInfo (used in %s) did not record enough information to convert a %s into a %s.",
430  vers, buf.GetParent() ? buf.GetParent()->GetName() : "memory/socket", oldClass->GetName(), newClass->GetName() );
431  return 0;
432  }
433 
434  Version_t vClVersion = 0; // For vers less than 9, we have to use the current version.
435  if( vers >= 9 ) {
436  vClVersion = buf.ReadVersionForMemberWise( cle->GetCollectionProxy()->GetValueClass() );
437  }
438 
439  TVirtualCollectionProxy *newProxy = (newClass ? newClass->GetCollectionProxy() : nullptr);
440  TVirtualCollectionProxy *oldProxy = oldClass->GetCollectionProxy();
441  TStreamerInfo *subinfo = nullptr;
442 
443  if( newProxy ) {
444  // coverity[dereference] oldProxy->GetValueClass() can not be null since this was streamed memberwise.
445  subinfo = (TStreamerInfo*)newProxy->GetValueClass()->GetConversionStreamerInfo( oldProxy->GetValueClass(), vClVersion );
446  } else {
447  subinfo = (TStreamerInfo*)oldProxy->GetValueClass()->GetStreamerInfo( vClVersion );
448  newProxy = oldProxy;
449  }
450  if (subinfo) {
451  // DOLOOP {
452  void* env;
453  void **contp = (void**)((char *) addr + ioffset);
454  for(int j=0;j<config->fCompInfo->fLength;j++) {
455  void *cont = contp[j];
456  if (cont==nullptr) {
457  contp[j] = cle->New();
458  cont = contp[j];
459  }
460  TVirtualCollectionProxy::TPushPop helper( newProxy, cont );
461  Int_t nobjects;
462  buf >> nobjects;
463  env = newProxy->Allocate(nobjects,true);
464  subinfo->ReadBufferSTL(buf,newProxy,nobjects,/* offset */ 0, vers>=7 );
465  newProxy->Commit(env);
466  }
467  // } // DOLOOP
468  }
469  buf.CheckByteCount(start,count,aElement->GetFullName());
470  return 0;
471  }
472 
473  if (kIsTextT) {
474  // use same method which is used in kSTL
475  buf.ReadFastArray((void **)((char *)addr + ioffset), cle, config->fCompInfo->fLength, kFALSE, pstreamer);
476  } else if (pstreamer == nullptr) {
477  // DOLOOP {
478  void **contp = (void **)((char *)addr + ioffset);
479  for (int j = 0; j < config->fCompInfo->fLength; j++) {
480  void *cont = contp[j];
481  if (cont == nullptr) {
482  // int R__n;
483  // b >> R__n;
484  // b.SetOffset(b.GetOffset()-4); // rewind to the start of the int
485  // if (R__n) continue;
486  contp[j] = cle->New();
487  cont = contp[j];
488  }
489  cle->Streamer(cont, buf);
490  }
491  // }
492  } else {
493  (*pstreamer)(buf, (char *)addr + ioffset, config->fCompInfo->fLength);
494  }
495  buf.CheckByteCount(start, count, aElement->GetFullName());
496 
497  return 0;
498  }
499 
500  /** Direct copy of code from TStreamerInfo::WriteBufferAux,
501  * potentially can be used later for non-text streaming */
502  template<bool kIsTextT>
503  INLINE_TEMPLATE_ARGS Int_t WriteStreamerLoop(TBuffer &buf, void *addr, const TConfiguration *config)
504  {
505  UInt_t eoffset = 0; // extra parameter of TStreamerInfo::WriteBufferAux, 0 for all kind of objects writing
506  UInt_t ioffset = eoffset + config->fOffset;
507 
508  if (!kIsTextT && config->fCompInfo->fStreamer) {
509  // Get any private streamer which was set for the data member.
510  TMemberStreamer* pstreamer = config->fCompInfo->fStreamer;
511  // -- We have a private streamer.
512  UInt_t pos = buf.WriteVersion(config->fInfo->IsA(), kTRUE);
513  // Loop over the entries in the clones array or the STL container.
514  //for (int k = 0; k < narr; ++k) {
515  // Get a pointer to the counter for the varying length array.
516  Int_t* counter = (Int_t*) ((char *) addr /*entry pointer*/ + eoffset /*entry offset*/ + config->fCompInfo->fMethod /*counter offset*/);
517 
518  // And call the private streamer, passing it the buffer, the object, and the counter.
519  (*pstreamer)(buf, (char *) addr /*entry pointer*/ + ioffset /*object offset*/, *counter);
520  //} for k
521  buf.SetByteCount(pos, kTRUE);
522  // We are done, next streamer element.
523  return 0;
524  }
525 
526  // Get the class of the data member.
527  TClass* cl = config->fCompInfo->fClass;
528  // Which are we, an array of objects or an array of pointers to objects?
529  Bool_t isPtrPtr = (strstr(config->fCompInfo->fElem->GetTypeName(), "**") != 0);
530 
531  // By default assume the file version is the newest.
532  Int_t fileVersion = kMaxInt;
533 
534  if (!kIsTextT) {
535  // At this point we do *not* have a private streamer.
536  // Get the version of the file we are writing to.
537  TFile* file = (TFile*) buf.GetParent();
538  if (file) {
539  fileVersion = file->GetVersion();
540  }
541  }
542  // Write the class version to the buffer.
543  UInt_t pos = buf.WriteVersion(config->fInfo->IsA(), kTRUE);
544  if (fileVersion > 51508) {
545  // -- Newer versions allow polymorphic pointers to objects.
546  // Loop over the entries in the clones array or the STL container.
547  //for (int k = 0; k < narr; ++k) {
548  // Get the counter for the varying length array.
549  Int_t vlen = *((Int_t*) ((char *) addr /*entry pointer*/ + eoffset /*entry offset*/ + config->fCompInfo->fMethod /*counter offset*/));
550 
551  //b << vlen;
552  if (vlen) {
553  // Get a pointer to the array of pointers.
554  char** pp = (char**) ((char *) addr /*entry pointer*/ + ioffset /*object offset*/);
555  // Loop over each element of the array of pointers to varying-length arrays.
556  for (Int_t ndx = 0; ndx < config->fCompInfo->fLength; ++ndx) {
557  if (!pp[ndx]) {
558  // -- We do not have a pointer to a varying-length array.
559  // Error("WriteBufferAux", "The pointer to element %s::%s type %d (%s) is null\n", GetName(), aElement->GetFullName(), compinfo[i]->fType, aElement->GetTypeName());
560  // ::ErrorHandler(kError, "::WriteStreamerLoop", Form("The pointer to element %s::%s type %d (%s) is null\n", config->fInfo->GetName(), config->fCompInfo->fElem->GetFullName(), config->fCompInfo->fType, config->fCompInfo->fElem->GetTypeName()));
561  printf("WriteStreamerLoop - The pointer to element %s::%s type %d (%s) is null\n", config->fInfo->GetName(), config->fCompInfo->fElem->GetFullName(), config->fCompInfo->fType, config->fCompInfo->fElem->GetTypeName());
562  continue;
563  }
564  if (!isPtrPtr) {
565  // -- We are a varying-length array of objects.
566  // Write the entire array of objects to the buffer.
567  // Note: Polymorphism is not allowed here.
568  buf.WriteFastArray(pp[ndx], cl, vlen, nullptr);
569  } else {
570  // -- We are a varying-length array of pointers to objects.
571  // Write the entire array of object pointers to the buffer.
572  // Note: The object pointers are allowed to be polymorphic.
573  buf.WriteFastArray((void **)pp[ndx], cl, vlen, kFALSE, nullptr);
574  } // isPtrPtr
575  } // ndx
576  } else // vlen
577  if (kIsTextT) {
578  // special handling for the text-based streamers
579  for (Int_t ndx = 0; ndx < config->fCompInfo->fLength; ++ndx)
580  buf.WriteFastArray((void *)nullptr, cl, -1, nullptr);
581  }
582  //} // k
583  }
584  else {
585  // -- Older versions do *not* allow polymorphic pointers to objects.
586  // Loop over the entries in the clones array or the STL container.
587  //for (int k = 0; k < narr; ++k) {
588  // Get the counter for the varying length array.
589  Int_t vlen = *((Int_t*) ((char *) addr /*entry pointer*/ + eoffset /*entry offset*/ + config->fCompInfo->fMethod /*counter offset*/));
590  //b << vlen;
591  if (vlen) {
592  // Get a pointer to the array of pointers.
593  char** pp = (char**) ((char *) addr /*entry pointer*/ + ioffset /*object offset*/);
594  // -- Older versions do *not* allow polymorphic pointers to objects.
595  // Loop over each element of the array of pointers to varying-length arrays.
596  for (Int_t ndx = 0; ndx < config->fCompInfo->fLength; ++ndx) {
597  if (!pp[ndx]) {
598  // -- We do not have a pointer to a varying-length array.
599  //Error("WriteBufferAux", "The pointer to element %s::%s type %d (%s) is null\n", GetName(), aElement->GetFullName(), compinfo[i]->fType, aElement->GetTypeName());
600  // ::ErrorHandler(kError, "::WriteTextStreamerLoop", Form("The pointer to element %s::%s type %d (%s) is null\n", config->fInfo->GetName(), config->fCompInfo->fElem->GetFullName(), config->fCompInfo->fType, config->fCompInfo->fElem->GetTypeName()));
601  printf("WriteStreamerLoop - The pointer to element %s::%s type %d (%s) is null\n", config->fInfo->GetName(), config->fCompInfo->fElem->GetFullName(), config->fCompInfo->fType, config->fCompInfo->fElem->GetTypeName());
602  continue;
603  }
604  if (!isPtrPtr) {
605  // -- We are a varying-length array of objects.
606  // Loop over the elements of the varying length array.
607  for (Int_t v = 0; v < vlen; ++v) {
608  // Write the object to the buffer.
609  cl->Streamer(pp[ndx] + (v * cl->Size()), buf);
610  } // v
611  }
612  else {
613  // -- We are a varying-length array of pointers to objects.
614  // Loop over the elements of the varying length array.
615  for (Int_t v = 0; v < vlen; ++v) {
616  // Get a pointer to the object pointer.
617  char** r = (char**) pp[ndx];
618  // Write the object to the buffer.
619  cl->Streamer(r[v], buf);
620  } // v
621  } // isPtrPtr
622  } // ndx
623  } // vlen
624  //} // k
625  } // fileVersion
626  // Backpatch the byte count into the buffer.
627  buf.SetByteCount(pos, kTRUE);
628 
629  return 0;
630  }
631 
632 
633  /** Direct copy of code from TStreamerInfo::WriteBufferAux,
634  * potentially can be used later for non-text streaming */
635  template<bool kIsTextT>
636  INLINE_TEMPLATE_ARGS Int_t ReadStreamerLoop(TBuffer &buf, void *addr, const TConfiguration *config)
637  {
638  UInt_t eoffset = 0; // extra parameter of TStreamerInfo::WriteBufferAux, 0 for all kind of objects writing
639  UInt_t ioffset = eoffset + config->fOffset;
640 
641  // Get the class of the data member.
642  TClass* cl = config->fCompInfo->fClass;
643 
644  // Check for a private streamer.
645  if (!kIsTextT && config->fCompInfo->fStreamer) {
646  // Get any private streamer which was set for the data member.
647  TMemberStreamer* pstreamer = config->fCompInfo->fStreamer;
648  // -- We have a private streamer.
649  // Read the class version and byte count from the buffer.
650  UInt_t start = 0;
651  UInt_t count = 0;
652  buf.ReadVersion(&start, &count, cl);
653  // Loop over the entries in the clones array or the STL container.
654  //for (Int_t k = 0; k < narr; ++k) {
655 
656  Int_t* counter = (Int_t*) ((char *) addr /*entry pointer*/ + eoffset /*entry offset*/ + config->fCompInfo->fMethod /*counter offset*/);
657  // And call the private streamer, passing it the buffer, the object, and the counter.
658  (*pstreamer)(buf, (char *) addr /*entry pointer*/ + ioffset /*object offset*/, *counter);
659 
660  // } // for k
661  buf.CheckByteCount(start, count, config->fCompInfo->fElem->GetFullName());
662  // We are done, next streamer element.
663  return 0;
664  }
665 
666  // Which are we, an array of objects or an array of pointers to objects?
667  Bool_t isPtrPtr = (strstr(config->fCompInfo->fElem->GetTypeName(), "**") != 0);
668 
669  // By default assume the file version is the newest.
670  Int_t fileVersion = kMaxInt;
671  if (!kIsTextT) {
672  // At this point we do *not* have a private streamer.
673  // Get the version of the file we are reading from.
674  TFile* file = (TFile*) buf.GetParent();
675  if (file) {
676  fileVersion = file->GetVersion();
677  }
678  }
679  // Read the class version and byte count from the buffer.
680  UInt_t start = 0;
681  UInt_t count = 0;
682  buf.ReadVersion(&start, &count, cl);
683  if (fileVersion > 51508) {
684  // -- Newer versions allow polymorphic pointers.
685  // Loop over the entries in the clones array or the STL container.
686  // for (Int_t k = 0; k < narr; ++k) {
687  // Get the counter for the varying length array.
688  Int_t vlen = *((Int_t *)((char *)addr /*entry pointer*/ + eoffset /*entry offset*/ +
689  config->fCompInfo->fMethod /*counter offset*/));
690  // Int_t realLen;
691  // b >> realLen;
692  // if (realLen != vlen) {
693  // fprintf(stderr, "read vlen: %d realLen: %s\n", vlen, realLen);
694  //}
695  // Get a pointer to the array of pointers.
696  char **pp = (char **)((char *)addr /*entry pointer*/ + ioffset /*object offset*/);
697  // Loop over each element of the array of pointers to varying-length arrays.
698  // if (!pp) {
699  // continue;
700  // }
701 
702  if (pp) // SL: place it here instead of continue, which is related to for(k) loop
703  for (Int_t ndx = 0; ndx < config->fCompInfo->fLength; ++ndx) {
704  // if (!pp[ndx]) {
705  // -- We do not have a pointer to a varying-length array.
706  // Error("ReadBuffer", "The pointer to element %s::%s type %d (%s) is null\n", thisVar->GetName(),
707  // aElement->GetFullName(), compinfo[i]->fType, aElement->GetTypeName());
708  // continue;
709  //}
710  // Delete any memory at pp[ndx].
711  if (!isPtrPtr) {
712  cl->DeleteArray(pp[ndx]);
713  pp[ndx] = 0;
714  } else {
715  // Using vlen is wrong here because it has already
716  // been overwritten with the value needed to read
717  // the current record. Fixing this will require
718  // doing a pass over the object at the beginning
719  // of the I/O and releasing all the buffer memory
720  // for varying length arrays before we overwrite
721  // the counter values.
722  //
723  // For now we will just leak memory, just as we
724  // have always done in the past. Fix this.
725  //
726  // char** r = (char**) pp[ndx];
727  // if (r) {
728  // for (Int_t v = 0; v < vlen; ++v) {
729  // cl->Destructor(r[v]);
730  // r[v] = 0;
731  // }
732  //}
733  delete[] pp[ndx];
734  pp[ndx] = 0;
735  }
736  if (!vlen) {
737  if (kIsTextT) {
738  // special handling for the text-based streamers - keep calling to shift array index
739  buf.ReadFastArray((void *)nullptr, cl, -1, nullptr);
740  }
741  continue;
742  }
743  // Note: We now have pp[ndx] is null.
744  // Allocate memory to read into.
745  if (!isPtrPtr) {
746  // -- We are a varying-length array of objects.
747  // Note: Polymorphism is not allowed here.
748  // Allocate a new array of objects to read into.
749  pp[ndx] = (char *)cl->NewArray(vlen);
750  if (!pp[ndx]) {
751  Error("ReadBuffer", "Memory allocation failed!\n");
752  continue;
753  }
754  } else {
755  // -- We are a varying-length array of pointers to objects.
756  // Note: The object pointers are allowed to be polymorphic.
757  // Allocate a new array of pointers to objects to read into.
758  pp[ndx] = (char *)new char *[vlen];
759  if (!pp[ndx]) {
760  Error("ReadBuffer", "Memory allocation failed!\n");
761  continue;
762  }
763  // And set each pointer to null.
764  memset(pp[ndx], 0, vlen * sizeof(char *)); // This is the right size we really have a char**: pp[ndx]
765  // = (char*) new char*[vlen];
766  }
767  if (!isPtrPtr) {
768  // -- We are a varying-length array of objects.
769  buf.ReadFastArray(pp[ndx], cl, vlen, nullptr);
770  } else {
771  // -- We are a varying-length array of object pointers.
772  buf.ReadFastArray((void **)pp[ndx], cl, vlen, kFALSE, nullptr);
773  } // isPtrPtr
774  } // ndx
775  // } // k
776  } else {
777  // -- Older versions do *not* allow polymorphic pointers.
778  // Loop over the entries in the clones array or the STL container.
779  // for (Int_t k = 0; k < narr; ++k) {
780  // Get the counter for the varying length array.
781  Int_t vlen = *((Int_t *)((char *)addr /*entry pointer*/ + eoffset /*entry offset*/ +
782  config->fCompInfo->fMethod /*counter offset*/));
783  // Int_t realLen;
784  // b >> realLen;
785  // if (realLen != vlen) {
786  // fprintf(stderr, "read vlen: %d realLen: %s\n", vlen, realLen);
787  //}
788  // Get a pointer to the array of pointers.
789  char **pp = (char **)((char *)addr /*entry pointer*/ + ioffset /*object offset*/);
790  // if (!pp) {
791  // continue;
792  //}
793 
794  if (pp) // SL: place it here instead of continue, which is related to for(k) loop
795 
796  // Loop over each element of the array of pointers to varying-length arrays.
797  for (Int_t ndx = 0; ndx < config->fCompInfo->fLength; ++ndx) {
798  // if (!pp[ndx]) {
799  // -- We do not have a pointer to a varying-length array.
800  // Error("ReadBuffer", "The pointer to element %s::%s type %d (%s) is null\n", thisVar->GetName(),
801  // aElement->GetFullName(), compinfo[i]->fType, aElement->GetTypeName());
802  // continue;
803  //}
804  // Delete any memory at pp[ndx].
805  if (!isPtrPtr) {
806  cl->DeleteArray(pp[ndx]);
807  pp[ndx] = 0;
808  } else {
809  // Using vlen is wrong here because it has already
810  // been overwritten with the value needed to read
811  // the current record. Fixing this will require
812  // doing a pass over the object at the beginning
813  // of the I/O and releasing all the buffer memory
814  // for varying length arrays before we overwrite
815  // the counter values.
816  //
817  // For now we will just leak memory, just as we
818  // have always done in the past. Fix this.
819  //
820  // char** r = (char**) pp[ndx];
821  // if (r) {
822  // for (Int_t v = 0; v < vlen; ++v) {
823  // cl->Destructor(r[v]);
824  // r[v] = 0;
825  // }
826  //}
827  delete[] pp[ndx];
828  pp[ndx] = 0;
829  }
830  if (!vlen) {
831  continue;
832  }
833  // Note: We now have pp[ndx] is null.
834  // Allocate memory to read into.
835  if (!isPtrPtr) {
836  // -- We are a varying-length array of objects.
837  // Note: Polymorphism is not allowed here.
838  // Allocate a new array of objects to read into.
839  pp[ndx] = (char *)cl->NewArray(vlen);
840  if (!pp[ndx]) {
841  Error("ReadBuffer", "Memory allocation failed!\n");
842  continue;
843  }
844  } else {
845  // -- We are a varying-length array of pointers to objects.
846  // Note: The object pointers are allowed to be polymorphic.
847  // Allocate a new array of pointers to objects to read into.
848  pp[ndx] = (char *)new char *[vlen];
849  if (!pp[ndx]) {
850  Error("ReadBuffer", "Memory allocation failed!\n");
851  continue;
852  }
853  // And set each pointer to null.
854  memset(pp[ndx], 0, vlen * sizeof(char *)); // This is the right size we really have a char**: pp[ndx]
855  // = (char*) new char*[vlen];
856  }
857  if (!isPtrPtr) {
858  // -- We are a varying-length array of objects.
859  // Loop over the elements of the varying length array.
860  for (Int_t v = 0; v < vlen; ++v) {
861  // Read the object from the buffer.
862  cl->Streamer(pp[ndx] + (v * cl->Size()), buf);
863  } // v
864  } else {
865  // -- We are a varying-length array of object pointers.
866  // Get a pointer to the object pointer array.
867  char **r = (char **)pp[ndx];
868  // Loop over the elements of the varying length array.
869  for (Int_t v = 0; v < vlen; ++v) {
870  // Allocate an object to read into.
871  r[v] = (char *)cl->New();
872  if (!r[v]) {
873  // Do not print a second error message here.
874  // Error("ReadBuffer", "Memory allocation failed!\n");
875  continue;
876  }
877  // Read the object from the buffer.
878  cl->Streamer(r[v], buf);
879  } // v
880  } // isPtrPtr
881  } // ndx
882  // } // k
883  } // fileVersion
884  buf.CheckByteCount(start, count, config->fCompInfo->fElem->GetFullName());
885  return 0;
886  }
887 
888  class TConfWithFactor : public TConfiguration {
889  // Configuration object for the Float16/Double32 where a factor has been specified.
890  public:
891  Double_t fFactor;
892  Double_t fXmin;
893  TConfWithFactor(TVirtualStreamerInfo *info, UInt_t id, TCompInfo_t *compinfo, Int_t offset, Double_t factor, Double_t xmin) : TConfiguration(info,id,compinfo,offset),fFactor(factor),fXmin(xmin) {};
894  virtual TConfiguration *Copy() { return new TConfWithFactor(*this); }
895  };
896 
897  template <typename T>
898  INLINE_TEMPLATE_ARGS Int_t ReadBasicType_WithFactor(TBuffer &buf, void *addr, const TConfiguration *config)
899  {
900  // Stream a Float16 or Double32 where a factor has been specified.
901  //a range was specified. We read an integer and convert it back to a double.
902 
903  TConfWithFactor *conf = (TConfWithFactor *)config;
904  buf.ReadWithFactor((T*)( ((char*)addr) + config->fOffset ), conf->fFactor, conf->fXmin);
905  return 0;
906  }
907 
908  class TConfNoFactor : public TConfiguration {
909  // Configuration object for the Float16/Double32 where a factor has been specified.
910  public:
911  Int_t fNbits;
912  TConfNoFactor(TVirtualStreamerInfo *info, UInt_t id, TCompInfo_t *compinfo, Int_t offset, Int_t nbits) : TConfiguration(info,id,compinfo,offset),fNbits(nbits) {};
913  virtual TConfiguration *Copy() { return new TConfNoFactor(*this); }
914  };
915 
916  template <typename T>
917  INLINE_TEMPLATE_ARGS Int_t ReadBasicType_NoFactor(TBuffer &buf, void *addr, const TConfiguration *config)
918  {
919  // Stream a Float16 or Double32 where a factor has not been specified.
920 
921  TConfNoFactor *conf = (TConfNoFactor *)config;
922  Int_t nbits = conf->fNbits;
923 
924  buf.ReadWithNbits( (T*)( ((char*)addr) + config->fOffset ), nbits );
925  return 0;
926  }
927 
928  INLINE_TEMPLATE_ARGS Int_t ReadTString(TBuffer &buf, void *addr, const TConfiguration *config)
929  {
930  // Read in a TString object.
931 
932  // Idea: We could separate the TString Streamer in its two parts and
933  // avoid the if (buf.IsReading()) and try having it inlined.
934  ((TString*)(((char*)addr)+config->fOffset))->TString::Streamer(buf);
935  return 0;
936  }
937 
938  INLINE_TEMPLATE_ARGS Int_t ReadTObject(TBuffer &buf, void *addr, const TConfiguration *config)
939  {
940  // Read in a TObject object part.
941 
942  // Idea: We could separate the TObject Streamer in its two parts and
943  // avoid the if (buf.IsReading()).
944  ((TObject*)(((char*)addr)+config->fOffset))->TObject::Streamer(buf);
945  return 0;
946  }
947 
948  INLINE_TEMPLATE_ARGS Int_t ReadTNamed(TBuffer &buf, void *addr, const TConfiguration *config)
949  {
950  // Read in a TNamed object part.
951  // Since the TNamed streamer is solely delegating back to the StreamerInfo we
952  // can skip the streamer.
953 
954  // Idea: We could extract the code from ReadClassBuffer and avoid one function
955  // code.
956  static const TClass *TNamed_cl = TNamed::Class();
957  return buf.ReadClassBuffer(TNamed_cl,(((char*)addr)+config->fOffset));
958  }
959 
960  class TConfigSTL : public TConfiguration {
961  // Configuration object for the kSTL case
962  private:
963  void Init() {
964  TVirtualCollectionProxy *proxy = fNewClass->GetCollectionProxy();
965  if (proxy) {
966  fCreateIterators = proxy->GetFunctionCreateIterators();
967  fCopyIterator = proxy->GetFunctionCopyIterator();
968  fDeleteIterator = proxy->GetFunctionDeleteIterator();
969  fDeleteTwoIterators = proxy->GetFunctionDeleteTwoIterators();
970  }
971  }
972 
973  public:
974  TClass *fOldClass; // Class of the content on file
975  TClass *fNewClass; // Class of the content in memory.
976  TMemberStreamer *fStreamer;
977  const char *fTypeName; // Type name of the member as typed by ther user.
978  Bool_t fIsSTLBase; // aElement->IsBase() && aElement->IsA()!=TStreamerBase::Class()
979 
980  TVirtualCollectionProxy::CreateIterators_t fCreateIterators;
981  TVirtualCollectionProxy::CopyIterator_t fCopyIterator;
982  TVirtualCollectionProxy::DeleteIterator_t fDeleteIterator;
983  TVirtualCollectionProxy::DeleteTwoIterators_t fDeleteTwoIterators;
984 
985  TConfigSTL(TVirtualStreamerInfo *info, UInt_t id, TCompInfo_t *compinfo, Int_t offset, UInt_t length, TClass *oldClass, const char *type_name, Bool_t isbase) :
986  TConfiguration(info,id,compinfo,offset,length), fOldClass(oldClass), fNewClass(oldClass), fStreamer(0), fTypeName(type_name), fIsSTLBase(isbase),
987  fCreateIterators(0), fCopyIterator(0), fDeleteIterator(0), fDeleteTwoIterators(0) { Init(); }
988 
989  TConfigSTL(TVirtualStreamerInfo *info, UInt_t id, TCompInfo_t *compinfo, Int_t offset, UInt_t length, TClass *oldClass, TClass *newClass, const char *type_name, Bool_t isbase) :
990  TConfiguration(info,id,compinfo,offset,length), fOldClass(oldClass), fNewClass(newClass), fStreamer(0), fTypeName(type_name), fIsSTLBase(isbase),
991  fCreateIterators(0), fCopyIterator(0), fDeleteIterator(0), fDeleteTwoIterators(0) { Init(); }
992 
993  TConfigSTL(TVirtualStreamerInfo *info, UInt_t id, TCompInfo_t *compinfo, Int_t offset, UInt_t length, TClass *oldClass, TMemberStreamer* streamer, const char *type_name, Bool_t isbase) :
994  TConfiguration(info,id,compinfo,offset,length), fOldClass(oldClass), fNewClass(oldClass), fStreamer(streamer), fTypeName(type_name), fIsSTLBase(isbase),
995  fCreateIterators(0), fCopyIterator(0), fDeleteIterator(0), fDeleteTwoIterators(0) { Init(); }
996 
997  TConfigSTL(TVirtualStreamerInfo *info, UInt_t id, TCompInfo_t *compinfo, Int_t offset, UInt_t length, TClass *oldClass, TClass *newClass, TMemberStreamer* streamer, const char *type_name, Bool_t isbase) :
998  TConfiguration(info,id,compinfo,offset,length), fOldClass(oldClass), fNewClass(newClass), fStreamer(streamer), fTypeName(type_name), fIsSTLBase(isbase),
999  fCreateIterators(0), fCopyIterator(0), fDeleteIterator(0), fDeleteTwoIterators(0) { Init(); }
1000 
1001  virtual TConfiguration *Copy() { return new TConfigSTL(*this); }
1002  };
1003 
1004  class TConfSTLWithFactor : public TConfigSTL {
1005  // Configuration object for the Float16/Double32 where a factor has been specified.
1006  public:
1007  Double_t fFactor;
1008  Double_t fXmin;
1009  TConfSTLWithFactor(TConfigSTL *orig, Double_t factor, Double_t xmin) : TConfigSTL(*orig),fFactor(factor),fXmin(xmin) {};
1010  virtual TConfiguration *Copy() { return new TConfSTLWithFactor(*this); }
1011  };
1012 
1013  class TConfSTLNoFactor : public TConfigSTL {
1014  // Configuration object for the Float16/Double32 where a factor has been specified.
1015  public:
1016  Int_t fNbits;
1017  TConfSTLNoFactor(TConfigSTL *orig, Int_t nbits) : TConfigSTL(*orig),fNbits(nbits) {};
1018  virtual TConfiguration *Copy() { return new TConfSTLNoFactor(*this); }
1019  };
1020 
1021  class TVectorLoopConfig : public TLoopConfiguration {
1022  // Base class of the Configurations used in member wise streaming.
1023  protected:
1024  public:
1025  Long_t fIncrement; // Either a value to increase the cursor by and
1026  public:
1027  TVectorLoopConfig(TVirtualCollectionProxy *proxy, Long_t increment, Bool_t /* read */) : TLoopConfiguration(proxy), fIncrement(increment) {};
1028  //virtual void PrintDebug(TBuffer &buffer, void *);
1029  virtual ~TVectorLoopConfig() {};
1030  void Print() const
1031  {
1032  printf("TVectorLoopConfig: increment=%ld\n",fIncrement);
1033  }
1034 
1035  void* GetFirstAddress(void *start, const void * /* end */) const
1036  {
1037  // Return the address of the first element of the collection.
1038 
1039  return start;
1040  }
1041 
1042  virtual TLoopConfiguration* Copy() const { return new TVectorLoopConfig(*this); }
1043  };
1044 
1045  class TAssocLoopConfig : public TLoopConfiguration {
1046  // Base class of the Configurations used in member wise streaming.
1047  public:
1048  TAssocLoopConfig(TVirtualCollectionProxy *proxy, Bool_t /* read */) : TLoopConfiguration(proxy) {};
1049  //virtual void PrintDebug(TBuffer &buffer, void *);
1050  virtual ~TAssocLoopConfig() {};
1051  void Print() const
1052  {
1053  printf("TAssocLoopConfig: proxy=%s\n",fProxy->GetCollectionClass()->GetName());
1054  }
1055  virtual TLoopConfiguration* Copy() const { return new TAssocLoopConfig(*this); }
1056 
1057  void* GetFirstAddress(void *start, const void * /* end */) const
1058  {
1059  // Return the address of the first element of the collection.
1060 
1061  R__ASSERT(0);
1062 // char iterator[TVirtualCollectionProxy::fgIteratorArenaSize];
1063 // void *iter = genloopconfig->fCopyIterator(&iterator,start_collection);
1064 // arr0 = genloopconfig->fNext(iter,end_collection);
1065 // if (iter != &iterator[0]) {
1066 // genloopconfig->fDeleteIterator(iter);
1067 // }
1068  return start;
1069  }
1070  };
1071 
1072  class TGenericLoopConfig : public TLoopConfiguration {
1073  // Configuration object for the generic case of member wise streaming looping.
1074  private:
1075  void Init(Bool_t read) {
1076  if (fProxy) {
1077  if (fProxy->HasPointers()) {
1078  fNext = TVirtualCollectionPtrIterators::Next;
1079  fCopyIterator = TVirtualCollectionPtrIterators::CopyIterator;
1080  fDeleteIterator = TVirtualCollectionPtrIterators::DeleteIterator;
1081  } else {
1082  fNext = fProxy->GetFunctionNext(read);
1083  fCopyIterator = fProxy->GetFunctionCopyIterator(read);
1084  fDeleteIterator = fProxy->GetFunctionDeleteIterator(read);
1085  }
1086  }
1087  }
1088  public:
1089  TVirtualCollectionProxy::Next_t fNext;
1090  TVirtualCollectionProxy::CopyIterator_t fCopyIterator;
1091  TVirtualCollectionProxy::DeleteIterator_t fDeleteIterator;
1092 
1093  TGenericLoopConfig(TVirtualCollectionProxy *proxy, Bool_t read) : TLoopConfiguration(proxy), fNext(0), fCopyIterator(0), fDeleteIterator(0)
1094  {
1095  Init(read);
1096  }
1097  virtual ~TGenericLoopConfig() {};
1098  void Print() const
1099  {
1100  printf("TGenericLoopConfig: proxy=%s\n",fProxy->GetCollectionClass()->GetName());
1101  }
1102  virtual TLoopConfiguration* Copy() const { return new TGenericLoopConfig(*this); }
1103 
1104  void* GetFirstAddress(void *start_collection, const void *end_collection) const
1105  {
1106  // Return the address of the first element of the collection.
1107 
1108  char iterator[TVirtualCollectionProxy::fgIteratorArenaSize];
1109  void *iter = fCopyIterator(&iterator,start_collection);
1110  void *arr0 = fNext(iter,end_collection);
1111  if (iter != &iterator[0]) {
1112  fDeleteIterator(iter);
1113  }
1114  return arr0;
1115  }
1116  };
1117 
1118  INLINE_TEMPLATE_ARGS void ReadSTLMemberWiseSameClass(TBuffer &buf, void *addr, const TConfiguration *conf, Version_t vers)
1119  {
1120  // Collection was saved member-wise
1121 
1122  TConfigSTL *config = (TConfigSTL*)conf;
1123  vers &= ~( TBufferFile::kStreamedMemberWise );
1124 
1125  if( vers >= 8 ) {
1126 
1127  TClass *oldClass = config->fOldClass;
1128 
1129  TVirtualCollectionProxy *oldProxy = oldClass->GetCollectionProxy();
1130  if (!oldProxy) {
1131  // Missing information, broken file ... give up
1132  return;
1133  }
1134  TClass *valueClass = oldProxy->GetValueClass();
1135  Version_t vClVersion = buf.ReadVersionForMemberWise( valueClass );
1136 
1137  TVirtualCollectionProxy::TPushPop helper( oldProxy, (char*)addr );
1138  Int_t nobjects;
1139  buf.ReadInt(nobjects);
1140  void* alternative = oldProxy->Allocate(nobjects,true);
1141  if (nobjects) {
1142  TActionSequence *actions = oldProxy->GetReadMemberWiseActions( vClVersion );
1143 
1144  char startbuf[TVirtualCollectionProxy::fgIteratorArenaSize];
1145  char endbuf[TVirtualCollectionProxy::fgIteratorArenaSize];
1146  void *begin = &(startbuf[0]);
1147  void *end = &(endbuf[0]);
1148  config->fCreateIterators(alternative, &begin, &end, oldProxy);
1149  // We can not get here with a split vector of pointer, so we can indeed assume
1150  // that actions->fConfiguration != null.
1151  buf.ApplySequence(*actions, begin, end);
1152  if (begin != &(startbuf[0])) {
1153  // assert(end != endbuf);
1154  config->fDeleteTwoIterators(begin,end);
1155  }
1156  }
1157  oldProxy->Commit(alternative);
1158 
1159  } else {
1160 
1161  TClass *oldClass = config->fOldClass;
1162 
1163  TVirtualCollectionProxy *oldProxy = oldClass->GetCollectionProxy();
1164  if (!oldProxy) {
1165  // Missing information, broken file ... give up
1166  return;
1167  }
1168 
1169  TVirtualCollectionProxy::TPushPop helper( oldProxy, (char*)addr );
1170  Int_t nobjects;
1171  buf.ReadInt(nobjects);
1172  void* env = oldProxy->Allocate(nobjects,true);
1173 
1174  if (nobjects || vers < 7 ) {
1175  // coverity[dereference] since this is a member streaming action by definition the collection contains objects.
1176  TStreamerInfo *subinfo = (TStreamerInfo*)oldProxy->GetValueClass()->GetStreamerInfo( 0 );
1177 
1178  subinfo->ReadBufferSTL(buf, oldProxy, nobjects, /* offset */ 0, /* v7 */ kFALSE);
1179  }
1180  oldProxy->Commit(env);
1181  }
1182  }
1183 
1184  INLINE_TEMPLATE_ARGS void ReadArraySTLMemberWiseSameClass(TBuffer &buf, void *addr, const TConfiguration *conf, Version_t vers)
1185  {
1186  // Collection was saved member-wise
1187 
1188  TConfigSTL *config = (TConfigSTL*)conf;
1189  vers &= ~( TBufferFile::kStreamedMemberWise );
1190 
1191  if( vers >= 8 ) {
1192 
1193  TClass *oldClass = config->fOldClass;
1194 
1195  TVirtualCollectionProxy *oldProxy = oldClass->GetCollectionProxy();
1196  if (!oldProxy) {
1197  // Missing information, broken file ... give up
1198  return;
1199  }
1200  TClass *valueClass = oldProxy->GetValueClass();
1201  Version_t vClVersion = buf.ReadVersionForMemberWise( valueClass );
1202 
1203  TActionSequence *actions = oldProxy->GetReadMemberWiseActions( vClVersion );
1204 
1205  int objectSize = oldClass->Size();
1206  char *obj = (char*)addr;
1207  char *endobj = obj + conf->fLength*objectSize;
1208 
1209  for(; obj<endobj; obj+=objectSize) {
1210  Int_t nobjects;
1211  buf.ReadInt(nobjects);
1212  TVirtualCollectionProxy::TPushPop helper( oldProxy, (char*)obj );
1213  void* alternative = oldProxy->Allocate(nobjects,true);
1214  if (nobjects) {
1215  char startbuf[TVirtualCollectionProxy::fgIteratorArenaSize];
1216  char endbuf[TVirtualCollectionProxy::fgIteratorArenaSize];
1217  void *begin = &(startbuf[0]);
1218  void *end = &(endbuf[0]);
1219  config->fCreateIterators(alternative, &begin, &end, oldProxy);
1220  // We can not get here with a split vector of pointer, so we can indeed assume
1221  // that actions->fConfiguration != null.
1222  buf.ApplySequence(*actions, begin, end);
1223  if (begin != &(startbuf[0])) {
1224  // assert(end != endbuf);
1225  config->fDeleteTwoIterators(begin,end);
1226  }
1227  }
1228  oldProxy->Commit(alternative);
1229  }
1230 
1231  } else {
1232 
1233  TClass *oldClass = config->fOldClass;
1234 
1235  TVirtualCollectionProxy *oldProxy = oldClass->GetCollectionProxy();
1236  if (!oldProxy) {
1237  // Missing information, broken file ... give up
1238  return;
1239  }
1240 
1241  int objectSize = oldClass->Size();
1242  char *obj = (char*)addr;
1243  char *endobj = obj + conf->fLength*objectSize;
1244 
1245  for(; obj<endobj; obj+=objectSize) {
1246  TVirtualCollectionProxy::TPushPop helper( oldProxy, (char*)obj );
1247  Int_t nobjects;
1248  buf.ReadInt(nobjects);
1249  void* env = oldProxy->Allocate(nobjects,true);
1250 
1251  if (nobjects || vers < 7 ) {
1252  // coverity[dereference] since this is a member streaming action by definition the collection contains objects.
1253  TStreamerInfo *subinfo = (TStreamerInfo*)oldProxy->GetValueClass()->GetStreamerInfo( 0 );
1254 
1255  subinfo->ReadBufferSTL(buf, oldProxy, nobjects, /* offset */ 0, /* v7 */ kFALSE);
1256  }
1257  oldProxy->Commit(env);
1258  }
1259  }
1260  }
1261 
1262  INLINE_TEMPLATE_ARGS void ReadSTLMemberWiseChangedClass(TBuffer &buf, void *addr, const TConfiguration *conf, Version_t vers)
1263  {
1264  // Collection was saved member-wise
1265 
1266  TConfigSTL *config = (TConfigSTL*)conf;
1267 
1268  vers &= ~( TBufferFile::kStreamedMemberWise );
1269 
1270  TClass *newClass = config->fNewClass;
1271  TClass *oldClass = config->fOldClass;
1272 
1273  if( vers < 8 ) {
1274  Error( "ReadSTLMemberWiseChangedClass", "Unfortunately, version %d of TStreamerInfo (used in %s) did not record enough information to convert a %s into a %s.",
1275  vers, buf.GetParent() ? buf.GetParent()->GetName() : "memory/socket", oldClass->GetName(), newClass->GetName() );
1276  } else {
1277 
1278  Version_t vClVersion = buf.ReadVersionForMemberWise( oldClass->GetCollectionProxy()->GetValueClass() );
1279 
1280  TVirtualCollectionProxy *newProxy = newClass->GetCollectionProxy();
1281  TVirtualCollectionProxy *oldProxy = oldClass->GetCollectionProxy();
1282 
1283  TVirtualCollectionProxy::TPushPop helper( newProxy, (char*)addr );
1284  Int_t nobjects;
1285  buf.ReadInt(nobjects);
1286  void* alternative = newProxy->Allocate(nobjects,true);
1287  if (nobjects) {
1288  TActionSequence *actions = newProxy->GetConversionReadMemberWiseActions( oldProxy->GetValueClass(), vClVersion );
1289  char startbuf[TVirtualCollectionProxy::fgIteratorArenaSize];
1290  char endbuf[TVirtualCollectionProxy::fgIteratorArenaSize];
1291  void *begin = &(startbuf[0]);
1292  void *end = &(endbuf[0]);
1293  config->fCreateIterators( alternative, &begin, &end, newProxy);
1294  // We can not get here with a split vector of pointer, so we can indeed assume
1295  // that actions->fConfiguration != null.
1296  buf.ApplySequence(*actions, begin, end);
1297  if (begin != &(startbuf[0])) {
1298  // assert(end != endbuf);
1299  config->fDeleteTwoIterators(begin,end);
1300  }
1301  }
1302  newProxy->Commit(alternative);
1303  }
1304  }
1305 
1306  INLINE_TEMPLATE_ARGS void ReadArraySTLMemberWiseChangedClass(TBuffer &buf, void *addr, const TConfiguration *conf, Version_t vers)
1307  {
1308  // Collection was saved member-wise
1309 
1310  TConfigSTL *config = (TConfigSTL*)conf;
1311 
1312  vers &= ~( TBufferFile::kStreamedMemberWise );
1313 
1314  TClass *newClass = config->fNewClass;
1315  TClass *oldClass = config->fOldClass;
1316 
1317  if( vers < 8 ) {
1318  Error( "ReadSTLMemberWiseChangedClass", "Unfortunately, version %d of TStreamerInfo (used in %s) did not record enough information to convert a %s into a %s.",
1319  vers, buf.GetParent() ? buf.GetParent()->GetName() : "memory/socket", oldClass->GetName(), newClass->GetName() );
1320  } else {
1321 
1322  Version_t vClVersion = buf.ReadVersionForMemberWise( oldClass->GetCollectionProxy()->GetValueClass() );
1323 
1324  TVirtualCollectionProxy *newProxy = newClass->GetCollectionProxy();
1325  TVirtualCollectionProxy *oldProxy = oldClass->GetCollectionProxy();
1326 
1327  int objectSize = newClass->Size();
1328  char *obj = (char*)addr;
1329  char *endobj = obj + conf->fLength*objectSize;
1330 
1331  for(; obj<endobj; obj+=objectSize) {
1332  TVirtualCollectionProxy::TPushPop helper( newProxy, (char*)obj );
1333  Int_t nobjects;
1334  buf.ReadInt(nobjects);
1335  void* alternative = newProxy->Allocate(nobjects,true);
1336  if (nobjects) {
1337  TActionSequence *actions = newProxy->GetConversionReadMemberWiseActions( oldProxy->GetValueClass(), vClVersion );
1338  char startbuf[TVirtualCollectionProxy::fgIteratorArenaSize];
1339  char endbuf[TVirtualCollectionProxy::fgIteratorArenaSize];
1340  void *begin = &(startbuf[0]);
1341  void *end = &(endbuf[0]);
1342  config->fCreateIterators( alternative, &begin, &end, newProxy);
1343  // We can not get here with a split vector of pointer, so we can indeed assume
1344  // that actions->fConfiguration != null.
1345  buf.ApplySequence(*actions, begin, end);
1346  if (begin != &(startbuf[0])) {
1347  // assert(end != endbuf);
1348  config->fDeleteTwoIterators(begin,end);
1349  }
1350  }
1351  newProxy->Commit(alternative);
1352  }
1353  }
1354  }
1355 
1356 
1357  INLINE_TEMPLATE_ARGS void ReadSTLObjectWiseFastArray(TBuffer &buf, void *addr, const TConfiguration *conf, Version_t /* vers */, UInt_t /* start */)
1358  {
1359  TConfigSTL *config = (TConfigSTL*)conf;
1360  // Idea: This needs to be unrolled, it currently calls the TGenCollectionStreamer ....
1361  buf.ReadFastArray(addr,config->fNewClass,conf->fLength,(TMemberStreamer*)0,config->fOldClass);
1362  }
1363  INLINE_TEMPLATE_ARGS void ReadSTLObjectWiseStreamer(TBuffer &buf, void *addr, const TConfiguration *conf, Version_t /* vers */, UInt_t /* start */)
1364  {
1365  TConfigSTL *config = (TConfigSTL*)conf;
1366  (*config->fStreamer)(buf,addr,conf->fLength);
1367  }
1368  INLINE_TEMPLATE_ARGS void ReadSTLObjectWiseFastArrayV2(TBuffer &buf, void *addr, const TConfiguration *conf, Version_t vers, UInt_t start)
1369  {
1370  // case of old TStreamerInfo
1371 
1372  TConfigSTL *config = (TConfigSTL*)conf;
1373  // Backward compatibility. Some TStreamerElement's where without
1374  // Streamer but were not removed from element list
1375  if (config->fIsSTLBase || vers == 0) {
1376  buf.SetBufferOffset(start); //there is no byte count
1377  }
1378  // Idea: This needs to be unrolled, it currently calls the TGenCollectionStreamer ....
1379  buf.ReadFastArray(addr,config->fNewClass,conf->fLength,(TMemberStreamer*)0,config->fOldClass);
1380  }
1381  INLINE_TEMPLATE_ARGS void ReadSTLObjectWiseStreamerV2(TBuffer &buf, void *addr, const TConfiguration *conf, Version_t vers, UInt_t start)
1382  {
1383  // case of old TStreamerInfo
1384 
1385  TConfigSTL *config = (TConfigSTL*)conf;
1386  // Backward compatibility. Some TStreamerElement's where without
1387  // Streamer but were not removed from element list
1388  if (config->fIsSTLBase || vers == 0) {
1389  buf.SetBufferOffset(start); //there is no byte count
1390  }
1391  (*config->fStreamer)(buf,addr,conf->fLength);
1392  }
1393 
1394  template <void (*memberwise)(TBuffer&,void *,const TConfiguration*, Version_t),
1395  void (*objectwise)(TBuffer&,void *,const TConfiguration*, Version_t, UInt_t)>
1396  INLINE_TEMPLATE_ARGS Int_t ReadSTL(TBuffer &buf, void *addr, const TConfiguration *conf)
1397  {
1398  TConfigSTL *config = (TConfigSTL*)conf;
1399  UInt_t start, count;
1400  Version_t vers = buf.ReadVersion(&start, &count, config->fOldClass);
1401  if ( vers & TBufferFile::kStreamedMemberWise ) {
1402  memberwise(buf,((char*)addr)+config->fOffset,config, vers);
1403  } else {
1404  objectwise(buf,((char*)addr)+config->fOffset,config, vers, start);
1405  }
1406  buf.CheckByteCount(start,count,config->fTypeName);
1407  return 0;
1408  }
1409 
1410  template <typename From, typename To>
1411  struct ConvertBasicType {
1412  static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *addr, const TConfiguration *config)
1413  {
1414  // Simple conversion from a 'From' on disk to a 'To' in memory.
1415  From temp;
1416  buf >> temp;
1417  *(To*)( ((char*)addr) + config->fOffset ) = (To)temp;
1418  return 0;
1419  }
1420  };
1421 
1422  template <typename To>
1423  struct ConvertBasicType<BitsMarker,To> {
1424  static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *addr, const TConfiguration *config)
1425  {
1426  // Simple conversion from a 'From' on disk to a 'To' in memory
1427  UInt_t temp;
1428  buf >> temp;
1429 
1430  if ((temp & kIsReferenced) != 0) {
1431  HandleReferencedTObject(buf,addr,config);
1432  }
1433 
1434  *(To*)( ((char*)addr) + config->fOffset ) = (To)temp;
1435  return 0;
1436  }
1437  };
1438 
1439  template <typename From, typename To>
1440  struct ConvertBasicType<WithFactorMarker<From>,To> {
1441  static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *addr, const TConfiguration *config)
1442  {
1443  // Simple conversion from a 'From' on disk to a 'To' in memory.
1444  TConfWithFactor *conf = (TConfWithFactor *)config;
1445  From temp;
1446  buf.ReadWithFactor(&temp, conf->fFactor, conf->fXmin);
1447  *(To*)( ((char*)addr) + config->fOffset ) = (To)temp;
1448  return 0;
1449  }
1450  };
1451 
1452  template <typename From, typename To>
1453  struct ConvertBasicType<NoFactorMarker<From>,To> {
1454  static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *addr, const TConfiguration *config)
1455  {
1456  // Simple conversion from a 'From' on disk to a 'To' in memory.
1457  TConfNoFactor *conf = (TConfNoFactor *)config;
1458  From temp;
1459  buf.ReadWithNbits(&temp, conf->fNbits);
1460  *(To*)( ((char*)addr) + config->fOffset ) = (To)temp;
1461  return 0;
1462  }
1463  };
1464 
1465  class TConfigurationPushDataCache : public TConfiguration {
1466  // Configuration object for the PushDataCache case.
1467  public:
1468  TVirtualArray *fOnfileObject;
1469 
1470  TConfigurationPushDataCache(TVirtualStreamerInfo *info, TVirtualArray *onfileObject, Int_t offset) :
1471  TConfiguration(info, -1, nullptr, offset), fOnfileObject(onfileObject)
1472  {}
1473 
1474  virtual void Print() const {
1475  TStreamerInfo *info = (TStreamerInfo*)fInfo;
1476  if (fOnfileObject)
1477  printf("StreamerInfoAction, class:%s, PushDataCache offset=%d\n",
1478  info->GetClass()->GetName(), fOffset);
1479  else
1480  printf("StreamerInfoAction, class:%s, PopDataCache offset=%d\n",
1481  info->GetClass()->GetName(), fOffset);
1482  }
1483  virtual void PrintDebug(TBuffer &buffer, void *object) const {
1484  if (gDebug > 1) {
1485  TStreamerInfo *info = (TStreamerInfo*)fInfo;
1486  printf("StreamerInfoAction, class:%s, %sDataCache, bufpos=%d, arr=%p, offset=%d, onfileObject=%p\n",
1487  info->GetClass()->GetName(), fOnfileObject ? "Push" : "Pop", buffer.Length(), object, fOffset, fOnfileObject);
1488 
1489  }
1490  }
1491  };
1492 
1493  Int_t PushDataCache(TBuffer &b, void *, const TConfiguration *conf)
1494  {
1495  TConfigurationPushDataCache *config = (TConfigurationPushDataCache*)conf;
1496  auto onfileObject = config->fOnfileObject;
1497 
1498  // onfileObject->SetSize(1);
1499  b.PushDataCache( onfileObject );
1500 
1501  return 0;
1502  }
1503 
1504  Int_t PushDataCacheGenericCollection(TBuffer &b, void *, const void *, const TLoopConfiguration *loopconfig, const TConfiguration *conf)
1505  {
1506  TConfigurationPushDataCache *config = (TConfigurationPushDataCache*)conf;
1507  auto onfileObject = config->fOnfileObject;
1508 
1509  TVirtualCollectionProxy *proxy = ((TGenericLoopConfig*)loopconfig)->fProxy;
1510  UInt_t n = proxy->Size();
1511 
1512  onfileObject->SetSize(n);
1513  b.PushDataCache( onfileObject );
1514 
1515  return 0;
1516  }
1517 
1518  Int_t PopDataCache(TBuffer &b, void *, const TConfiguration *)
1519  {
1520  b.PopDataCache();
1521  return 0;
1522  }
1523 
1524  Int_t PopDataCacheGenericCollection(TBuffer &b, void *, const void *, const TLoopConfiguration *, const TConfiguration *)
1525  {
1526  b.PopDataCache();
1527  return 0;
1528  }
1529 
1530  class TConfigurationUseCache : public TConfiguration {
1531  // Configuration object for the UseCache case.
1532  public:
1533  TConfiguredAction fAction;
1534  Bool_t fNeedRepeat;
1535 
1536  TConfigurationUseCache(TVirtualStreamerInfo *info, TConfiguredAction &action, Bool_t repeat) :
1537  TConfiguration(info,action.fConfiguration->fElemId,action.fConfiguration->fCompInfo,action.fConfiguration->fOffset),fAction(action),fNeedRepeat(repeat) {};
1538  virtual void PrintDebug(TBuffer &b, void *addr) const
1539  {
1540  if (gDebug > 1) {
1541  // Idea: We should print the name of the action function.
1542  TStreamerInfo *info = (TStreamerInfo*)fInfo;
1543  TStreamerElement *aElement = fCompInfo->fElem;
1544  fprintf(stdout,"StreamerInfoAction, class:%s, name=%s, fType[%d]=%d,"
1545  " %s, bufpos=%d, arr=%p, eoffset=%d, Redirect=%p\n",
1546  info->GetClass()->GetName(),aElement->GetName(),fElemId,fCompInfo->fType,
1547  aElement->ClassName(),b.Length(),addr, 0,b.PeekDataCache() ? b.PeekDataCache()->GetObjectAt(0) : 0);
1548  }
1549 
1550  }
1551  virtual ~TConfigurationUseCache() {};
1552  virtual TConfiguration *Copy() {
1553  TConfigurationUseCache *copy = new TConfigurationUseCache(*this);
1554  fAction.fConfiguration = copy->fAction.fConfiguration->Copy(); // since the previous allocation did a 'move' of fAction we need to fix it.
1555  return copy;
1556  }
1557  };
1558 
1559  INLINE_TEMPLATE_ARGS Int_t UseCache(TBuffer &b, void *addr, const TConfiguration *conf)
1560  {
1561  TConfigurationUseCache *config = (TConfigurationUseCache*)conf;
1562 
1563  Int_t bufpos = b.Length();
1564  TVirtualArray *cached = b.PeekDataCache();
1565  if (cached==0) {
1566  TStreamerElement *aElement = conf->fCompInfo->fElem;
1567  TStreamerInfo *info = (TStreamerInfo*)conf->fInfo;
1568  Warning("ReadBuffer","Skipping %s::%s because the cache is missing.",info->GetName(),aElement->GetName());
1569  char *ptr = (char*)addr;
1570  info->ReadBufferSkip(b,&ptr,config->fCompInfo,config->fCompInfo->fType+TStreamerInfo::kSkip,aElement,1,0);
1571  } else {
1572  config->fAction(b, (*cached)[0]);
1573  }
1574  // Idea: Factor out this 'if' to a UseCacheRepeat function
1575  if (config->fNeedRepeat) {
1576  b.SetBufferOffset(bufpos);
1577  }
1578  return 0;
1579  }
1580 
1581  INLINE_TEMPLATE_ARGS Int_t UseCacheVectorPtrLoop(TBuffer &b, void *start, const void *end, const TConfiguration *conf)
1582  {
1583  TConfigurationUseCache *config = (TConfigurationUseCache*)conf;
1584  Int_t bufpos = b.Length();
1585 
1586  TVirtualArray *cached = b.PeekDataCache();
1587  if (cached==0) {
1588  TStreamerElement *aElement = config->fCompInfo->fElem;
1589  TStreamerInfo *info = (TStreamerInfo*)config->fInfo;
1590  Warning("ReadBuffer","Skipping %s::%s because the cache is missing.",info->GetName(),aElement->GetName());
1591  char *ptr = (char*)start;
1592  UInt_t n = (((void**)end)-((void**)start));
1593  info->ReadBufferSkip(b,&ptr,config->fCompInfo,conf->fCompInfo->fType+TStreamerInfo::kSkip,aElement,n,0);
1594  } else {
1595  TVectorLoopConfig cached_config( nullptr, cached->fClass->Size(), /* read */ kTRUE );
1596  void *cached_start = (*cached)[0];
1597  void *cached_end = ((char*)cached_start) + cached->fSize * cached_config.fIncrement;
1598  config->fAction(b,cached_start,cached_end,&cached_config);
1599  }
1600  // Idea: Factor out this 'if' to a UseCacheRepeat function
1601  if (config->fNeedRepeat) {
1602  b.SetBufferOffset(bufpos);
1603  }
1604  return 0;
1605  }
1606 
1607  INLINE_TEMPLATE_ARGS Int_t UseCacheVectorLoop(TBuffer &b, void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration *conf)
1608  {
1609  TConfigurationUseCache *config = (TConfigurationUseCache*)conf;
1610 
1611  Int_t bufpos = b.Length();
1612  TVirtualArray *cached = b.PeekDataCache();
1613  if (cached==0) {
1614  TStreamerElement *aElement = config->fCompInfo->fElem;
1615  TStreamerInfo *info = (TStreamerInfo*)config->fInfo;
1616  Warning("ReadBuffer","Skipping %s::%s because the cache is missing.",info->GetName(),aElement->GetName());
1617  char *ptr = (char*)start;
1618  UInt_t n = (((char*)end)-((char*)start))/((TVectorLoopConfig*)loopconf)->fIncrement;
1619  info->ReadBufferSkip(b,&ptr,config->fCompInfo,config->fCompInfo->fType+TStreamerInfo::kSkip,aElement,n,0);
1620  } else {
1621  TVectorLoopConfig cached_config( nullptr, cached->fClass->Size(), /* read */ kTRUE );
1622  void *cached_start = (*cached)[0];
1623  void *cached_end = ((char*)cached_start) + cached->fSize * cached_config.fIncrement;
1624  config->fAction(b,cached_start,cached_end,&cached_config);
1625  }
1626  // Idea: Factor out this 'if' to a UseCacheRepeat function
1627  if (config->fNeedRepeat) {
1628  b.SetBufferOffset(bufpos);
1629  }
1630  return 0;
1631  }
1632 
1633  INLINE_TEMPLATE_ARGS Int_t UseCacheGenericCollection(TBuffer &b, void *, const void *, const TLoopConfiguration *loopconfig, const TConfiguration *conf)
1634  {
1635  TConfigurationUseCache *config = (TConfigurationUseCache*)conf;
1636 
1637  Int_t bufpos = b.Length();
1638  TVirtualArray *cached = b.PeekDataCache();
1639  if (cached==0) {
1640  TStreamerElement *aElement = config->fCompInfo->fElem;
1641  TStreamerInfo *info = (TStreamerInfo*)config->fInfo;
1642 
1643  TVirtualCollectionProxy *proxy = ((TGenericLoopConfig*)loopconfig)->fProxy;
1644  Warning("ReadBuffer","Skipping %s::%s because the cache is missing.",info->GetName(),aElement->GetName());
1645  UInt_t n = proxy->Size();
1646  info->ReadBufferSkip(b, *proxy,config->fCompInfo,config->fCompInfo->fType+TStreamerInfo::kSkip,aElement,n,0);
1647  } else {
1648  TVectorLoopConfig cached_config( nullptr, cached->fClass->Size(), /* read */ kTRUE );
1649  void *cached_start = (*cached)[0];
1650  void *cached_end = ((char*)cached_start) + cached->fSize * cached_config.fIncrement;
1651  config->fAction(b,cached_start,cached_end,&cached_config);
1652  }
1653  // Idea: Factor out this 'if' to a UseCacheRepeat function
1654  if (config->fNeedRepeat) {
1655  b.SetBufferOffset(bufpos);
1656  }
1657  return 0;
1658  }
1659 
1660  // Support for collections.
1661 
1662  Int_t ReadLoopInvalid(TBuffer &, void *, const void *, const TConfiguration *config)
1663  {
1664  Fatal("ApplySequence","The sequence of actions to read %s:%d member-wise was not initialized.",config->fInfo->GetName(),config->fInfo->GetClassVersion());
1665  return 0;
1666  }
1667 
1668  Int_t WriteLoopInvalid(TBuffer &, void *, const void *, const TConfiguration *config)
1669  {
1670  Fatal("ApplySequence","The sequence of actions to write %s:%d member-wise was not initialized.",config->fInfo->GetName(),config->fInfo->GetClassVersion());
1671  return 0;
1672  }
1673 
1674  enum ESelectLooper { kVectorLooper, kVectorPtrLooper, kAssociativeLooper, kGenericLooper };
1675 
1676  ESelectLooper SelectLooper(TVirtualCollectionProxy &proxy)
1677  {
1678  if ( (proxy.GetCollectionType() == ROOT::kSTLvector) || (proxy.GetProperties() & TVirtualCollectionProxy::kIsEmulated) ) {
1679  if (proxy.GetProperties() & TVirtualCollectionProxy::kCustomAlloc)
1680  return kGenericLooper;
1681  else
1682  return kVectorLooper;
1683  } else if (proxy.GetCollectionType() == ROOT::kSTLset || proxy.GetCollectionType() == ROOT::kSTLunorderedset
1684  || proxy.GetCollectionType() == ROOT::kSTLmultiset || proxy.GetCollectionType() == ROOT::kSTLunorderedmultiset
1685  || proxy.GetCollectionType() == ROOT::kSTLmap || proxy.GetCollectionType() == ROOT::kSTLmultimap
1686  || proxy.GetCollectionType() == ROOT::kSTLunorderedmap || proxy.GetCollectionType() == ROOT::kSTLunorderedmultimap
1687  || proxy.GetCollectionType() == ROOT::kSTLbitset) {
1688  return kAssociativeLooper;
1689  } else {
1690  return kGenericLooper;
1691  }
1692  }
1693 
1694  struct VectorLooper {
1695 
1696  template <typename T>
1697  static INLINE_TEMPLATE_ARGS Int_t ReadBasicType(TBuffer &buf, void *iter, const void *end, const TLoopConfiguration *loopconfig, const TConfiguration *config)
1698  {
1699  const Int_t incr = ((TVectorLoopConfig*)loopconfig)->fIncrement;
1700  iter = (char*)iter + config->fOffset;
1701  end = (char*)end + config->fOffset;
1702  for(; iter != end; iter = (char*)iter + incr ) {
1703  T *x = (T*) ((char*) iter);
1704  buf >> *x;
1705  }
1706  return 0;
1707  }
1708 
1709  template <typename From, typename To>
1710  struct ConvertBasicType {
1711  static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *iter, const void *end, const TLoopConfiguration *loopconfig, const TConfiguration *config)
1712  {
1713  // Simple conversion from a 'From' on disk to a 'To' in memory.
1714  From temp;
1715  const Int_t incr = ((TVectorLoopConfig*)loopconfig)->fIncrement;
1716  iter = (char*)iter + config->fOffset;
1717  end = (char*)end + config->fOffset;
1718  for(; iter != end; iter = (char*)iter + incr ) {
1719  buf >> temp;
1720  *(To*)( ((char*)iter) ) = (To)temp;
1721  }
1722  return 0;
1723  }
1724  };
1725 
1726  template <typename To>
1727  struct ConvertBasicType<BitsMarker,To> {
1728  static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *iter, const void *end, const TLoopConfiguration *loopconfig, const TConfiguration *config)
1729  {
1730  // Simple conversion from a 'From' on disk to a 'To' in memory.
1731  UInt_t temp;
1732  const Int_t incr = ((TVectorLoopConfig*)loopconfig)->fIncrement;
1733  iter = (char*)iter + config->fOffset;
1734  end = (char*)end + config->fOffset;
1735  for(; iter != end; iter = (char*)iter + incr ) {
1736  buf >> temp;
1737 
1738  if ((temp & kIsReferenced) != 0) {
1739  HandleReferencedTObject(buf, (char*)iter - config->fOffset, config);
1740  }
1741 
1742  *(To*)( ((char*)iter) ) = (To)temp;
1743  }
1744  return 0;
1745  }
1746  };
1747 
1748  template <typename From, typename To>
1749  struct ConvertBasicType<WithFactorMarker<From>,To> {
1750  static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *iter, const void *end, const TLoopConfiguration *loopconfig, const TConfiguration *config)
1751  {
1752  // Simple conversion from a 'From' on disk to a 'To' in memory.
1753  TConfWithFactor *conf = (TConfWithFactor *)config;
1754  From temp;
1755  const Int_t incr = ((TVectorLoopConfig*)loopconfig)->fIncrement;
1756  iter = (char*)iter + config->fOffset;
1757  end = (char*)end + config->fOffset;
1758  for(; iter != end; iter = (char*)iter + incr ) {
1759  buf.ReadWithFactor(&temp, conf->fFactor, conf->fXmin);
1760  *(To*)( ((char*)iter) ) = (To)temp;
1761  }
1762  return 0;
1763  }
1764  };
1765 
1766  template <typename From, typename To>
1767  struct ConvertBasicType<NoFactorMarker<From>,To> {
1768  static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *iter, const void *end, const TLoopConfiguration *loopconfig, const TConfiguration *config)
1769  {
1770  // Simple conversion from a 'From' on disk to a 'To' in memory.
1771  TConfNoFactor *conf = (TConfNoFactor *)config;
1772  From temp;
1773  const Int_t incr = ((TVectorLoopConfig*)loopconfig)->fIncrement;
1774  iter = (char*)iter + config->fOffset;
1775  end = (char*)end + config->fOffset;
1776  for(; iter != end; iter = (char*)iter + incr ) {
1777  buf.ReadWithNbits(&temp, conf->fNbits);
1778  *(To*)( ((char*)iter) ) = (To)temp;
1779  }
1780  return 0;
1781  }
1782  };
1783 
1784  template <typename T>
1785  static INLINE_TEMPLATE_ARGS Int_t WriteBasicType(TBuffer &buf, void *iter, const void *end, const TLoopConfiguration *loopconfig, const TConfiguration *config)
1786  {
1787  const Int_t incr = ((TVectorLoopConfig*)loopconfig)->fIncrement;
1788  iter = (char*)iter + config->fOffset;
1789  end = (char*)end + config->fOffset;
1790  for(; iter != end; iter = (char*)iter + incr ) {
1791  T *x = (T*) ((char*) iter);
1792  buf << *x;
1793  }
1794  return 0;
1795  }
1796 
1797  template <Int_t (*iter_action)(TBuffer&,void *,const TConfiguration*)>
1798  static INLINE_TEMPLATE_ARGS Int_t ReadAction(TBuffer &buf, void *start, const void *end, const TLoopConfiguration *loopconfig, const TConfiguration *config)
1799  {
1800  const Int_t incr = ((TVectorLoopConfig*)loopconfig)->fIncrement;
1801  //Idea: can we factor out the addition of fOffset
1802  // iter = (char*)iter + config->fOffset;
1803  for(void *iter = start; iter != end; iter = (char*)iter + incr ) {
1804  iter_action(buf, iter, config);
1805  }
1806  return 0;
1807  }
1808 
1809  static INLINE_TEMPLATE_ARGS Int_t ReadBase(TBuffer &buf, void *start, const void *end, const TLoopConfiguration * loopconfig, const TConfiguration *config)
1810  {
1811  // Well the implementation is non trivial since we do not have a proxy for the container of _only_ the base class. For now
1812  // punt.
1813 
1814  UInt_t incr = ((TVectorLoopConfig*)loopconfig)->fIncrement;
1815  UInt_t n = (((char*)end)-((char*)start))/incr;
1816  char **arrptr = new char*[n];
1817  UInt_t i = 0;
1818  for(void *iter = start; iter != end; iter = (char*)iter + incr, ++i ) {
1819  arrptr[i] = (char*)iter;
1820  }
1821  ((TStreamerInfo*)config->fInfo)->ReadBuffer(buf, arrptr, &(config->fCompInfo), /*first*/ 0, /*last*/ 1, /*narr*/ n, config->fOffset, 1|2 );
1822  delete [] arrptr;
1823 
1824  // // Idea: need to cache this result!
1825  // TStreamerInfo *info = (TStreamerInfo*)config->fInfo;
1826  // TStreamerElement *aElement = (TStreamerElement*)info->GetElem(config->fElemId);
1827  //
1828  // *Int_t clversion = ((TStreamerBase*)aElement)->Get BaseVersion();
1829  // *TClass *cle = aElement->GetNewBaseClass();
1830  // *(TSequence *actions = CreateReadMemberWiseActions( cle->GetStreamerInfo(clversion), ???? );
1831  //
1832  // TSequence *actions = CreateReadMemberWiseActions( ((TStreamerBase*)aElement)->GetBaseStreamerInfo(), ???? );
1833  //
1834  // actions->ReadBuffer(b,start,end);
1835  // delete actions;
1836 
1837  // const Int_t incr = ((TVectorLoopConfig*)loopconfig)->fIncrement;
1838  // for(void *iter = start; iter != end; iter = (char*)iter + incr )
1839  // {
1840  // ((TStreamerInfo*)(((TStreamerBase*)aElement)->GetBaseStreamerInfo())->ReadBuffer(b,arr,-1,narr,ioffset,arrayMode);
1841  //
1842  // ((TStreamerInfo*)config->fInfo)->ReadBuffer(buf, (char**)&iter, config->fElemId, 1, config->fOffset, 1|2 );
1843  // }
1844  return 0;
1845  }
1846 
1847  static INLINE_TEMPLATE_ARGS Int_t GenericRead(TBuffer &buf, void *start, const void *end, const TLoopConfiguration * loopconfig, const TConfiguration *config)
1848  {
1849  // Well the implementation is non trivial. For now punt.
1850 
1851  UInt_t incr = ((TVectorLoopConfig*)loopconfig)->fIncrement;
1852  UInt_t n = (((char*)end)-((char*)start))/incr;
1853  char **arrptr = new char*[n];
1854  UInt_t i = 0;
1855  for(void *iter = start; iter != end; iter = (char*)iter + incr, ++i ) {
1856  arrptr[i] = (char*)iter;
1857  }
1858  ((TStreamerInfo*)config->fInfo)->ReadBuffer(buf, arrptr, &(config->fCompInfo), /*first*/ 0, /*last*/ 1, /*narr*/ n, config->fOffset, 1|2 );
1859  delete [] arrptr;
1860  return 0;
1861  }
1862 
1863  static INLINE_TEMPLATE_ARGS Int_t GenericWrite(TBuffer &buf, void *start, const void *end, const TLoopConfiguration * loopconfig, const TConfiguration *config)
1864  {
1865  // Well the implementation is non trivial. For now punt.
1866 
1867  UInt_t incr = ((TVectorLoopConfig*)loopconfig)->fIncrement;
1868  UInt_t n = (((char*)end)-((char*)start))/incr;
1869  char **arrptr = new char*[n];
1870  UInt_t i = 0;
1871  for(void *iter = start; iter != end; iter = (char*)iter + incr, ++i ) {
1872  arrptr[i] = (char*)iter;
1873  }
1874  ((TStreamerInfo*)config->fInfo)->WriteBufferAux(buf, arrptr, &(config->fCompInfo), /*first*/ 0, /*last*/ 1, n, config->fOffset, 1|2 );
1875  delete [] arrptr;
1876  return 0;
1877  }
1878 
1879  template <typename T>
1880  static INLINE_TEMPLATE_ARGS Int_t ReadCollectionBasicType(TBuffer &buf, void *addr, const TConfiguration *conf)
1881  {
1882  // Collection of numbers. Memberwise or not, it is all the same.
1883 
1884  TConfigSTL *config = (TConfigSTL*)conf;
1885  UInt_t start, count;
1886  /* Version_t vers = */ buf.ReadVersion(&start, &count, config->fOldClass);
1887 
1888  std::vector<T> *const vec = (std::vector<T>*)(((char*)addr)+config->fOffset);
1889  Int_t nvalues;
1890  buf.ReadInt(nvalues);
1891  vec->resize(nvalues);
1892 
1893 #ifdef R__VISUAL_CPLUSPLUS
1894  if (nvalues <= 0) {
1895  buf.CheckByteCount(start,count,config->fTypeName);
1896  return 0;
1897  }
1898 #endif
1899  T *begin = &(*vec->begin());
1900  buf.ReadFastArray(begin, nvalues);
1901 
1902  buf.CheckByteCount(start,count,config->fTypeName);
1903  return 0;
1904  }
1905 
1906  static INLINE_TEMPLATE_ARGS Int_t ReadCollectionBool(TBuffer &buf, void *addr, const TConfiguration *conf)
1907  {
1908  // Collection of numbers. Memberwise or not, it is all the same.
1909 
1910  TConfigSTL *config = (TConfigSTL*)conf;
1911  UInt_t start, count;
1912  /* Version_t vers = */ buf.ReadVersion(&start, &count, config->fOldClass);
1913 
1914  std::vector<bool> *const vec = (std::vector<bool>*)(((char*)addr)+config->fOffset);
1915  Int_t nvalues;
1916  buf.ReadInt(nvalues);
1917  vec->resize(nvalues);
1918 
1919  bool *items = new bool[nvalues];
1920  buf.ReadFastArray(items, nvalues);
1921  for(Int_t i = 0 ; i < nvalues; ++i) {
1922  (*vec)[i] = items[i];
1923  }
1924  delete [] items;
1925 
1926  // We could avoid the call to ReadFastArray, and we could
1927  // the following, however this breaks TBufferXML ...
1928  // for(Int_t i = 0 ; i < nvalues; ++i) {
1929  // bool tmp; buf >> tmp;
1930  // (*vec)[i] = tmp;
1931  // }
1932 
1933  buf.CheckByteCount(start,count,config->fTypeName);
1934  return 0;
1935  }
1936 
1937  static INLINE_TEMPLATE_ARGS Int_t ReadCollectionFloat16(TBuffer &buf, void *addr, const TConfiguration *conf)
1938  {
1939  // Collection of numbers. Memberwise or not, it is all the same.
1940 
1941  TConfigSTL *config = (TConfigSTL*)conf;
1942  UInt_t start, count;
1943  /* Version_t vers = */ buf.ReadVersion(&start, &count, config->fOldClass);
1944 
1945  std::vector<float> *const vec = (std::vector<float>*)(((char*)addr)+config->fOffset);
1946  Int_t nvalues;
1947  buf.ReadInt(nvalues);
1948  vec->resize(nvalues);
1949 
1950 #ifdef R__VISUAL_CPLUSPLUS
1951  if (nvalues <= 0) {
1952  buf.CheckByteCount(start,count,config->fTypeName);
1953  return 0;
1954  }
1955 #endif
1956  float *begin = &(*vec->begin());
1957  buf.ReadFastArrayFloat16(begin, nvalues);
1958 
1959  buf.CheckByteCount(start,count,config->fTypeName);
1960  return 0;
1961  }
1962 
1963  static INLINE_TEMPLATE_ARGS Int_t ReadCollectionDouble32(TBuffer &buf, void *addr, const TConfiguration *conf)
1964  {
1965  // Collection of numbers. Memberwise or not, it is all the same.
1966 
1967  TConfigSTL *config = (TConfigSTL*)conf;
1968  UInt_t start, count;
1969  /* Version_t vers = */ buf.ReadVersion(&start, &count, config->fOldClass);
1970 
1971  std::vector<double> *const vec = (std::vector<double>*)(((char*)addr)+config->fOffset);
1972  Int_t nvalues;
1973  buf.ReadInt(nvalues);
1974  vec->resize(nvalues);
1975 
1976 #ifdef R__VISUAL_CPLUSPLUS
1977  if (nvalues <= 0) {
1978  buf.CheckByteCount(start,count,config->fTypeName);
1979  return 0;
1980  }
1981 #endif
1982  double *begin = &(*vec->begin());
1983  buf.ReadFastArrayDouble32(begin, nvalues);
1984 
1985  buf.CheckByteCount(start,count,config->fTypeName);
1986  return 0;
1987  }
1988 
1989  template <typename From, typename To>
1990  struct ConvertCollectionBasicType {
1991  static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *addr, const TConfiguration *conf)
1992  {
1993  // Collection of numbers. Memberwise or not, it is all the same.
1994 
1995  TConfigSTL *config = (TConfigSTL*)conf;
1996  UInt_t start, count;
1997  /* Version_t vers = */ buf.ReadVersion(&start, &count, config->fOldClass);
1998 
1999  std::vector<To> *const vec = (std::vector<To>*)(((char*)addr)+config->fOffset);
2000  Int_t nvalues;
2001  buf.ReadInt(nvalues);
2002  vec->resize(nvalues);
2003 
2004  From *temp = new From[nvalues];
2005  buf.ReadFastArray(temp, nvalues);
2006  for(Int_t ind = 0; ind < nvalues; ++ind) {
2007  (*vec)[ind] = (To)temp[ind];
2008  }
2009  delete [] temp;
2010 
2011  buf.CheckByteCount(start,count,config->fTypeName);
2012  return 0;
2013  }
2014  };
2015 
2016  template <typename From, typename To>
2017  struct ConvertCollectionBasicType<NoFactorMarker<From>,To> {
2018  static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *addr, const TConfiguration *conf)
2019  {
2020  // Collection of numbers. Memberwise or not, it is all the same.
2021 
2022  TConfigSTL *config = (TConfigSTL*)conf;
2023  UInt_t start, count;
2024  /* Version_t vers = */ buf.ReadVersion(&start, &count, config->fOldClass);
2025 
2026  std::vector<To> *const vec = (std::vector<To>*)(((char*)addr)+config->fOffset);
2027  Int_t nvalues;
2028  buf.ReadInt(nvalues);
2029  vec->resize(nvalues);
2030 
2031  From *temp = new From[nvalues];
2032  buf.ReadFastArrayWithNbits(temp, nvalues, 0);
2033  for(Int_t ind = 0; ind < nvalues; ++ind) {
2034  (*vec)[ind] = (To)temp[ind];
2035  }
2036  delete [] temp;
2037 
2038  buf.CheckByteCount(start,count,config->fTypeName);
2039  return 0;
2040  }
2041  };
2042 
2043  template <typename To>
2044  static INLINE_TEMPLATE_ARGS Int_t ConvertCollectionDouble32(TBuffer &buf, void *addr, const TConfiguration *conf)
2045  {
2046  // Collection of numbers. Memberwise or not, it is all the same.
2047 
2048  TConfigSTL *config = (TConfigSTL*)conf;
2049  UInt_t start, count;
2050  /* Version_t vers = */ buf.ReadVersion(&start, &count, config->fOldClass);
2051 
2052  std::vector<To> *const vec = (std::vector<To>*)(((char*)addr)+config->fOffset);
2053  Int_t nvalues;
2054  buf.ReadInt(nvalues);
2055  vec->resize(nvalues);
2056 
2057  Double32_t *temp = new Double32_t[nvalues];
2058  buf.ReadFastArrayDouble32(temp, nvalues);
2059  for(Int_t ind = 0; ind < nvalues; ++ind) {
2060  (*vec)[ind] = (To)temp[ind];
2061  }
2062  delete [] temp;
2063 
2064  buf.CheckByteCount(start,count,config->fTypeName);
2065  return 0;
2066  }
2067 
2068  };
2069 
2070  struct VectorPtrLooper {
2071 
2072  template <typename T>
2073  static INLINE_TEMPLATE_ARGS Int_t ReadBasicType(TBuffer &buf, void *iter, const void *end, const TConfiguration *config)
2074  {
2075  const Int_t offset = config->fOffset;
2076 
2077  for(; iter != end; iter = (char*)iter + sizeof(void*) ) {
2078  T *x = (T*)( ((char*) (*(void**)iter) ) + offset );
2079  buf >> *x;
2080  }
2081  return 0;
2082  }
2083 
2084  template <typename From, typename To>
2085  struct ConvertBasicType {
2086  static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *iter, const void *end, const TConfiguration *config)
2087  {
2088  // Simple conversion from a 'From' on disk to a 'To' in memory.
2089  From temp;
2090  const Int_t offset = config->fOffset;
2091  for(; iter != end; iter = (char*)iter + sizeof(void*) ) {
2092  buf >> temp;
2093  To *x = (To*)( ((char*) (*(void**)iter) ) + offset );
2094  *x = (To)temp;
2095  }
2096  return 0;
2097  }
2098  };
2099 
2100  template <typename To>
2101  struct ConvertBasicType<BitsMarker,To> {
2102  static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *iter, const void *end, const TConfiguration *config)
2103  {
2104  // Simple conversion from a 'From' on disk to a 'To' in memory.
2105  UInt_t temp;
2106  const Int_t offset = config->fOffset;
2107  for(; iter != end; iter = (char*)iter + sizeof(void*) ) {
2108  buf >> temp;
2109 
2110  if ((temp & kIsReferenced) != 0) {
2111  HandleReferencedTObject(buf,*(void**)iter,config);
2112  }
2113 
2114  To *x = (To*)( ((char*) (*(void**)iter) ) + offset );
2115  *x = (To)temp;
2116  }
2117  return 0;
2118  }
2119  };
2120 
2121  template <typename From, typename To>
2122  struct ConvertBasicType<WithFactorMarker<From>,To> {
2123  static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *iter, const void *end, const TConfiguration *config)
2124  {
2125  // Simple conversion from a 'From' on disk to a 'To' in memory.
2126  TConfWithFactor *conf = (TConfWithFactor *)config;
2127  From temp;
2128  const Int_t offset = config->fOffset;
2129  for(; iter != end; iter = (char*)iter + sizeof(void*) ) {
2130  buf.ReadWithFactor(&temp, conf->fFactor, conf->fXmin);
2131  To *x = (To*)( ((char*) (*(void**)iter) ) + offset );
2132  *x = (To)temp;
2133  }
2134  return 0;
2135  }
2136  };
2137 
2138  template <typename From, typename To>
2139  struct ConvertBasicType<NoFactorMarker<From>,To> {
2140  static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *iter, const void *end, const TConfiguration *config)
2141  {
2142  // Simple conversion from a 'From' on disk to a 'To' in memory.
2143  TConfNoFactor *conf = (TConfNoFactor *)config;
2144  From temp;
2145  const Int_t offset = config->fOffset;
2146  for(; iter != end; iter = (char*)iter + sizeof(void*) ) {
2147  buf.ReadWithNbits(&temp, conf->fNbits);
2148  To *x = (To*)( ((char*) (*(void**)iter) ) + offset );
2149  *x = (To)temp;
2150  }
2151  return 0;
2152  }
2153  };
2154 
2155  template <typename T>
2156  static INLINE_TEMPLATE_ARGS Int_t WriteBasicType(TBuffer &buf, void *iter, const void *end, const TConfiguration *config)
2157  {
2158  const Int_t offset = config->fOffset;
2159 
2160  for(; iter != end; iter = (char*)iter + sizeof(void*) ) {
2161  T *x = (T*)( ((char*) (*(void**)iter) ) + offset );
2162  buf << *x;
2163  }
2164  return 0;
2165  }
2166 
2167  template <Int_t (*action)(TBuffer&,void *,const TConfiguration*)>
2168  static INLINE_TEMPLATE_ARGS Int_t ReadAction(TBuffer &buf, void *start, const void *end, const TConfiguration *config)
2169  {
2170  for(void *iter = start; iter != end; iter = (char*)iter + sizeof(void*) ) {
2171  action(buf, *(void**)iter, config);
2172  }
2173  return 0;
2174  }
2175 
2176  static INLINE_TEMPLATE_ARGS Int_t ReadBase(TBuffer &buf, void *start, const void *end, const TConfiguration *config)
2177  {
2178  // Well the implementation is non trivial since we do not have a proxy for the container of _only_ the base class. For now
2179  // punt.
2180 
2181  return GenericRead(buf,start,end,config);
2182  }
2183 
2184  static INLINE_TEMPLATE_ARGS Int_t GenericRead(TBuffer &buf, void *iter, const void *end, const TConfiguration *config)
2185  {
2186  Int_t n = ( ((void**)end) - ((void**)iter) );
2187  char **arr = (char**)iter;
2188  return ((TStreamerInfo*)config->fInfo)->ReadBuffer(buf, arr, &(config->fCompInfo), /*first*/ 0, /*last*/ 1, /*narr*/ n, config->fOffset, 1|2 );
2189  }
2190 
2191  static INLINE_TEMPLATE_ARGS Int_t GenericWrite(TBuffer &buf, void *iter, const void *end, const TConfiguration *config)
2192  {
2193  Int_t n = ( ((void**)end) - ((void**)iter) );
2194  char **arr = (char**)iter;
2195  return ((TStreamerInfo*)config->fInfo)->WriteBufferAux(buf, arr, &(config->fCompInfo), /*first*/ 0, /*last*/ 1, n, config->fOffset, 1|2 );
2196  }
2197 
2198  };
2199 
2200  struct AssociativeLooper {
2201 
2202  template <typename T>
2203  static INLINE_TEMPLATE_ARGS void SimpleRead(TBuffer &buf, void *addr, Int_t nvalues)
2204  {
2205  buf.ReadFastArray((T*)addr, nvalues);
2206  }
2207 
2208  static INLINE_TEMPLATE_ARGS void SimpleReadFloat16(TBuffer &buf, void *addr, Int_t nvalues)
2209  {
2210  buf.ReadFastArrayFloat16((float*)addr, nvalues);
2211  }
2212 
2213  static INLINE_TEMPLATE_ARGS void SimpleReadDouble32(TBuffer &buf, void *addr, Int_t nvalues)
2214  {
2215  buf.ReadFastArrayDouble32((double*)addr, nvalues);
2216  }
2217 
2218  template <typename T,void (*action)(TBuffer&,void *,Int_t)>
2219  static INLINE_TEMPLATE_ARGS Int_t ReadNumericalCollection(TBuffer &buf, void *addr, const TConfiguration *conf)
2220  {
2221  // Collection of numbers. Memberwise or not, it is all the same.
2222 
2223  TConfigSTL *config = (TConfigSTL*)conf;
2224  UInt_t start, count;
2225  /* Version_t vers = */ buf.ReadVersion(&start, &count, config->fOldClass);
2226 
2227  TClass *newClass = config->fNewClass;
2228  TVirtualCollectionProxy *newProxy = newClass->GetCollectionProxy();
2229  TVirtualCollectionProxy::TPushPop helper( newProxy, ((char*)addr)+config->fOffset );
2230 
2231  Int_t nvalues;
2232  buf.ReadInt(nvalues);
2233  void* alternative = newProxy->Allocate(nvalues,true);
2234  if (nvalues) {
2235  char startbuf[TVirtualCollectionProxy::fgIteratorArenaSize];
2236  char endbuf[TVirtualCollectionProxy::fgIteratorArenaSize];
2237  void *begin = &(startbuf[0]);
2238  void *end = &(endbuf[0]);
2239  config->fCreateIterators(alternative, &begin, &end, newProxy);
2240  // We can not get here with a split vector of pointer, so we can indeed assume
2241  // that actions->fConfiguration != null.
2242 
2243  action(buf,begin,nvalues);
2244 
2245  if (begin != &(startbuf[0])) {
2246  // assert(end != endbuf);
2247  config->fDeleteTwoIterators(begin,end);
2248  }
2249  }
2250  newProxy->Commit(alternative);
2251 
2252  buf.CheckByteCount(start,count,config->fTypeName);
2253  return 0;
2254  }
2255 
2256  static INLINE_TEMPLATE_ARGS Int_t ReadCollectionBool(TBuffer &buf, void *addr, const TConfiguration *conf)
2257  {
2258  return ReadNumericalCollection<bool,SimpleRead<bool> >(buf,addr,conf);
2259  }
2260 
2261  static INLINE_TEMPLATE_ARGS Int_t ReadCollectionFloat16(TBuffer &buf, void *addr, const TConfiguration *conf)
2262  {
2263  return ReadNumericalCollection<Float_t,SimpleReadFloat16 >(buf,addr,conf);
2264  }
2265 
2266  static INLINE_TEMPLATE_ARGS Int_t ReadCollectionDouble32(TBuffer &buf, void *addr, const TConfiguration *conf)
2267  {
2268  return ReadNumericalCollection<Double_t,SimpleReadDouble32 >(buf,addr,conf);
2269  }
2270 
2271  template <typename T>
2272  static INLINE_TEMPLATE_ARGS Int_t ReadCollectionBasicType(TBuffer &buf, void *addr, const TConfiguration *conf)
2273  {
2274  return ReadNumericalCollection<T,SimpleRead<T> >(buf,addr,conf);
2275  }
2276 
2277  template <typename From, typename To>
2278  struct ConvertRead {
2279  static INLINE_TEMPLATE_ARGS void Action(TBuffer &buf, void *addr, Int_t nvalues)
2280  {
2281  From *temp = new From[nvalues];
2282  buf.ReadFastArray(temp, nvalues);
2283  To *vec = (To*)addr;
2284  for(Int_t ind = 0; ind < nvalues; ++ind) {
2285  vec[ind] = (To)temp[ind];
2286  }
2287  delete [] temp;
2288  }
2289  };
2290 
2291  template <typename From, typename To>
2292  struct ConvertRead<NoFactorMarker<From>,To> {
2293  static INLINE_TEMPLATE_ARGS void Action(TBuffer &buf, void *addr, Int_t nvalues)
2294  {
2295  From *temp = new From[nvalues];
2296  buf.ReadFastArrayWithNbits(temp, nvalues,0);
2297  To *vec = (To*)addr;
2298  for(Int_t ind = 0; ind < nvalues; ++ind) {
2299  vec[ind] = (To)temp[ind];
2300  }
2301  delete [] temp;
2302  }
2303  };
2304 
2305  template <typename From, typename To>
2306  struct ConvertRead<WithFactorMarker<From>,To> {
2307  static INLINE_TEMPLATE_ARGS void Action(TBuffer &buf, void *addr, Int_t nvalues)
2308  {
2309  From *temp = new From[nvalues];
2310  double factor,min; // needs to be initialized.
2311  buf.ReadFastArrayWithFactor(temp, nvalues, factor, min);
2312  To *vec = (To*)addr;
2313  for(Int_t ind = 0; ind < nvalues; ++ind) {
2314  vec[ind] = (To)temp[ind];
2315  }
2316  delete [] temp;
2317  }
2318  };
2319 
2320  template <typename From, typename To>
2321  struct ConvertCollectionBasicType {
2322  static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *addr, const TConfiguration *conf)
2323  {
2324  return ReadNumericalCollection<To,ConvertRead<From,To>::Action >(buf,addr,conf);
2325  }
2326  };
2327 
2328  };
2329 
2330  struct GenericLooper {
2331 
2332  template <typename T>
2333  static INLINE_TEMPLATE_ARGS Int_t ReadBasicType(TBuffer &buf, void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration *config)
2334  {
2335  TGenericLoopConfig *loopconfig = (TGenericLoopConfig*)loopconf;
2336 
2337  Next_t next = loopconfig->fNext;
2338  const Int_t offset = config->fOffset;
2339 
2340  char iterator[TVirtualCollectionProxy::fgIteratorArenaSize];
2341  void *iter = loopconfig->fCopyIterator(iterator,start);
2342  void *addr;
2343  while( (addr = next(iter,end)) ) {
2344  T *x = (T*)( ((char*)addr) + offset );
2345  buf >> *x;
2346  }
2347  if (iter != &iterator[0]) {
2348  loopconfig->fDeleteIterator(iter);
2349  }
2350  return 0;
2351  }
2352 
2353  template <typename T>
2354  static INLINE_TEMPLATE_ARGS Int_t WriteBasicType(TBuffer &buf, void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration *config)
2355  {
2356  TGenericLoopConfig *loopconfig = (TGenericLoopConfig*)loopconf;
2357 
2358  Next_t next = loopconfig->fNext;
2359  const Int_t offset = config->fOffset;
2360 
2361  char iterator[TVirtualCollectionProxy::fgIteratorArenaSize];
2362  void *iter = loopconfig->fCopyIterator(iterator,start);
2363  void *addr;
2364  while( (addr = next(iter,end)) ) {
2365  T *x = (T*)( ((char*)addr) + offset );
2366  buf << *x;
2367  }
2368  if (iter != &iterator[0]) {
2369  loopconfig->fDeleteIterator(iter);
2370  }
2371  return 0;
2372  }
2373 
2374  template <Int_t (*iter_action)(TBuffer&,void *,const TConfiguration*)>
2375  static INLINE_TEMPLATE_ARGS Int_t ReadAction(TBuffer &buf, void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration *config)
2376  {
2377  TGenericLoopConfig *loopconfig = (TGenericLoopConfig*)loopconf;
2378 
2379  // const Int_t offset = config->fOffset;
2380  Next_t next = loopconfig->fNext;
2381 
2382  char iterator[TVirtualCollectionProxy::fgIteratorArenaSize];
2383  void *iter = loopconfig->fCopyIterator(&iterator,start);
2384  void *addr;
2385  while( (addr = next(iter,end)) ) {
2386  iter_action(buf, addr, config);
2387  }
2388  if (iter != &iterator[0]) {
2389  loopconfig->fDeleteIterator(iter);
2390  }
2391  return 0;
2392  }
2393 
2394  template <typename From, typename To>
2395  struct Generic {
2396  static void ConvertAction(From *items, void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration *config)
2397  {
2398  TGenericLoopConfig *loopconfig = (TGenericLoopConfig*)loopconf;
2399 
2400  const Int_t offset = config->fOffset;
2401  Next_t next = loopconfig->fNext;
2402 
2403  char iterator[TVirtualCollectionProxy::fgIteratorArenaSize];
2404  void *iter = loopconfig->fCopyIterator(&iterator,start);
2405  void *addr;
2406  while( (addr = next(iter,end)) ) {
2407  To *x = (To*)( ((char*)addr) + offset );
2408  *x = (To)(*items);
2409  ++items;
2410  }
2411  if (iter != &iterator[0]) {
2412  loopconfig->fDeleteIterator(iter);
2413  }
2414  }
2415  };
2416 
2417  template <typename From, typename To>
2418  struct Numeric {
2419  static void ConvertAction(From *items, void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration * /* config */)
2420  {
2421  // The difference with ConvertAction is that we can modify the start
2422  // iterator and skip the copy. We also never have an offset.
2423 
2424  TGenericLoopConfig *loopconfig = (TGenericLoopConfig*)loopconf;
2425  Next_t next = loopconfig->fNext;
2426 
2427  void *iter = start;
2428  void *addr;
2429  while( (addr = next(iter,end)) ) {
2430  To *x = (To*)(addr);
2431  *x = (To)(*items);
2432  ++items;
2433  }
2434  }
2435  };
2436 
2437  template <typename From, typename To, template <typename F, typename T> class Converter = Generic >
2438  struct ConvertBasicType {
2439  static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration *config)
2440  {
2441  // Simple conversion from a 'From' on disk to a 'To' in memory.
2442 
2443  TGenericLoopConfig *loopconfig = (TGenericLoopConfig*)loopconf;
2444  TVirtualCollectionProxy *proxy = loopconfig->fProxy;
2445  Int_t nvalues = proxy->Size();
2446 
2447  From *items = new From[nvalues];
2448  buf.ReadFastArray(items, nvalues);
2449  Converter<From,To>::ConvertAction(items,start,end,loopconfig,config);
2450  delete [] items;
2451  return 0;
2452  }
2453  };
2454 
2455  template <typename To>
2456  struct ConvertBasicType<BitsMarker, To, Generic> {
2457  static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration *config)
2458  {
2459  // Simple conversion from a 'From' on disk to a 'To' in memory.
2460 
2461  TGenericLoopConfig *loopconfig = (TGenericLoopConfig*)loopconf;
2462  TVirtualCollectionProxy *proxy = loopconfig->fProxy;
2463  Int_t nvalues = proxy->Size();
2464 
2465  UInt_t *items_storage = new UInt_t[nvalues];
2466  UInt_t *items = items_storage;
2467 
2468  const Int_t offset = config->fOffset;
2469  Next_t next = loopconfig->fNext;
2470 
2471  char iterator[TVirtualCollectionProxy::fgIteratorArenaSize];
2472  void *iter = loopconfig->fCopyIterator(&iterator,start);
2473  void *addr;
2474  while( (addr = next(iter,end)) ) {
2475  buf >> (*items);
2476  if (((*items) & kIsReferenced) != 0) {
2477  HandleReferencedTObject(buf, addr, config);
2478  }
2479  To *x = (To*)( ((char*)addr) + offset );
2480  *x = (To)(*items);
2481  ++items;
2482  }
2483  if (iter != &iterator[0]) {
2484  loopconfig->fDeleteIterator(iter);
2485  }
2486 
2487  delete [] items_storage;
2488  return 0;
2489  }
2490  };
2491 
2492  template <typename From, typename To, template <typename F, typename T> class Converter >
2493  struct ConvertBasicType<WithFactorMarker<From>,To,Converter > {
2494  static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration *config)
2495  {
2496  // Simple conversion from a 'From' on disk to a 'To' in memory.
2497 
2498  TGenericLoopConfig *loopconfig = (TGenericLoopConfig*)loopconf;
2499  TVirtualCollectionProxy *proxy = loopconfig->fProxy;
2500  Int_t nvalues = proxy->Size();
2501 
2502  TConfSTLWithFactor *conf = (TConfSTLWithFactor *)config;
2503 
2504  From *items = new From[nvalues];
2505  buf.ReadFastArrayWithFactor(items, nvalues, conf->fFactor, conf->fXmin);
2506  Converter<From,To>::ConvertAction(items,start,end,loopconfig,config);
2507  delete [] items;
2508  return 0;
2509  }
2510  };
2511 
2512  template <typename From, typename To, template <typename F, typename T> class Converter >
2513  struct ConvertBasicType<NoFactorMarker<From>,To,Converter > {
2514  static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration *config)
2515  {
2516  // Simple conversion from a 'From' on disk to a 'To' in memory.
2517 
2518  TGenericLoopConfig *loopconfig = (TGenericLoopConfig*)loopconf;
2519  TVirtualCollectionProxy *proxy = loopconfig->fProxy;
2520  Int_t nvalues = proxy->Size();
2521 
2522  TConfSTLNoFactor *conf = (TConfSTLNoFactor *)config;
2523 
2524  From *items = new From[nvalues];
2525  buf.ReadFastArrayWithNbits(items, nvalues, conf->fNbits);
2526  Converter<From,To>::ConvertAction(items,start,end,loopconfig,config);
2527  delete [] items;
2528  return 0;
2529  }
2530  };
2531 
2532  static INLINE_TEMPLATE_ARGS Int_t ReadBase(TBuffer &buf, void *start, const void *end, const TLoopConfiguration * loopconfig, const TConfiguration *config)
2533  {
2534  // Well the implementation is non trivial since we do not have a proxy for the container of _only_ the base class. For now
2535  // punt.
2536 
2537  return GenericRead(buf,start,end,loopconfig, config);
2538  }
2539 
2540  static INLINE_TEMPLATE_ARGS Int_t GenericRead(TBuffer &buf, void *, const void *, const TLoopConfiguration * loopconf, const TConfiguration *config)
2541  {
2542  TGenericLoopConfig *loopconfig = (TGenericLoopConfig*)loopconf;
2543  TVirtualCollectionProxy *proxy = loopconfig->fProxy;
2544  return ((TStreamerInfo*)config->fInfo)->ReadBuffer(buf, *proxy, &(config->fCompInfo), /*first*/ 0, /*last*/ 1, /*narr*/ proxy->Size(), config->fOffset, 1|2 );
2545  }
2546 
2547  static INLINE_TEMPLATE_ARGS Int_t GenericWrite(TBuffer &buf, void *, const void *, const TLoopConfiguration * loopconf, const TConfiguration *config)
2548  {
2549  TGenericLoopConfig *loopconfig = (TGenericLoopConfig*)loopconf;
2550  TVirtualCollectionProxy *proxy = loopconfig->fProxy;
2551  return ((TStreamerInfo*)config->fInfo)->WriteBufferAux(buf, *proxy, &(config->fCompInfo), /*first*/ 0, /*last*/ 1, proxy->Size(), config->fOffset, 1|2 );
2552  }
2553 
2554  template <typename T>
2555  static INLINE_TEMPLATE_ARGS void SimpleRead(TBuffer &buf, void *addr)
2556  {
2557  buf >> *(T*)addr;
2558  }
2559 
2560  static INLINE_TEMPLATE_ARGS void SimpleReadFloat16(TBuffer &buf, void *addr)
2561  {
2562  buf.ReadWithNbits((float*)addr,12);
2563  }
2564 
2565  static INLINE_TEMPLATE_ARGS void SimpleReadDouble32(TBuffer &buf, void *addr)
2566  {
2567  //we read a float and convert it to double
2568  Float_t afloat;
2569  buf >> afloat;
2570  *(double*)addr = (Double_t)afloat;
2571  }
2572 
2573  template <typename ActionHolder>
2574  static INLINE_TEMPLATE_ARGS Int_t ReadNumericalCollection(TBuffer &buf, void *addr, const TConfiguration *conf)
2575  {
2576  // Collection of numbers. Memberwise or not, it is all the same.
2577 
2578  TConfigSTL *config = (TConfigSTL*)conf;
2579  UInt_t start, count;
2580  /* Version_t vers = */ buf.ReadVersion(&start, &count, config->fOldClass);
2581 
2582  TClass *newClass = config->fNewClass;
2583  TVirtualCollectionProxy *newProxy = newClass->GetCollectionProxy();
2584  TVirtualCollectionProxy::TPushPop helper( newProxy, ((char*)addr)+config->fOffset );
2585 
2586  Int_t nvalues;
2587  buf.ReadInt(nvalues);
2588  void* alternative = newProxy->Allocate(nvalues,true);
2589  if (nvalues) {
2590  char startbuf[TVirtualCollectionProxy::fgIteratorArenaSize];
2591  char endbuf[TVirtualCollectionProxy::fgIteratorArenaSize];
2592  void *begin = &(startbuf[0]);
2593  void *end = &(endbuf[0]);
2594  config->fCreateIterators(alternative, &begin, &end, newProxy);
2595  // We can not get here with a split vector of pointer, so we can indeed assume
2596  // that actions->fConfiguration != null.
2597 
2598  TGenericLoopConfig loopconf(newProxy, /* read */ kTRUE);
2599  ActionHolder::Action(buf,begin,end,&loopconf,config);
2600 
2601  if (begin != &(startbuf[0])) {
2602  // assert(end != endbuf);
2603  config->fDeleteTwoIterators(begin,end);
2604  }
2605  }
2606  newProxy->Commit(alternative);
2607 
2608  buf.CheckByteCount(start,count,config->fTypeName);
2609  return 0;
2610  }
2611 
2612  static INLINE_TEMPLATE_ARGS Int_t ReadCollectionBool(TBuffer &buf, void *addr, const TConfiguration *conf)
2613  {
2614  return ReadNumericalCollection<ConvertBasicType<bool,bool,Numeric > >(buf,addr,conf);
2615  }
2616 
2617  static INLINE_TEMPLATE_ARGS Int_t ReadCollectionFloat16(TBuffer &buf, void *addr, const TConfiguration *conf)
2618  {
2619  return ReadNumericalCollection<ConvertBasicType<NoFactorMarker<float>,float,Numeric > >(buf,addr,conf);
2620  }
2621 
2622  static INLINE_TEMPLATE_ARGS Int_t ReadCollectionDouble32(TBuffer &buf, void *addr, const TConfiguration *conf)
2623  {
2624  return ReadNumericalCollection<ConvertBasicType<float,double,Numeric > >(buf,addr,conf);
2625  // Could also use:
2626  // return ReadNumericalCollection<ConvertBasicType<NoFactorMarker<double>,double,Numeric > >(buf,addr,conf);
2627  }
2628 
2629  template <typename T>
2630  static INLINE_TEMPLATE_ARGS Int_t ReadCollectionBasicType(TBuffer &buf, void *addr, const TConfiguration *conf)
2631  {
2632  return ReadNumericalCollection<ConvertBasicType<T,T,Numeric > >(buf,addr,conf);
2633  }
2634 
2635  template <typename From, typename To>
2636  struct ConvertCollectionBasicType {
2637  static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *addr, const TConfiguration *conf)
2638  {
2639  // return ReadNumericalCollection<To,ConvertRead<From,To>::Action >(buf,addr,conf);
2640  return ReadNumericalCollection<ConvertBasicType<From,To,Numeric > >(buf,addr,conf);
2641  }
2642  };
2643 
2644  };
2645 }
2646 
2647 template <typename Looper, typename From>
2648 static TConfiguredAction GetCollectionReadConvertAction(Int_t newtype, TConfiguration *conf)
2649 {
2650  switch (newtype) {
2651  case TStreamerInfo::kBool: return TConfiguredAction( Looper::template ConvertBasicType<From,bool>::Action, conf ); break;
2652  case TStreamerInfo::kChar: return TConfiguredAction( Looper::template ConvertBasicType<From,char>::Action, conf ); break;
2653  case TStreamerInfo::kShort: return TConfiguredAction( Looper::template ConvertBasicType<From,short>::Action, conf ); break;
2654  case TStreamerInfo::kInt: return TConfiguredAction( Looper::template ConvertBasicType<From,Int_t>::Action, conf ); break;
2655  case TStreamerInfo::kLong: return TConfiguredAction( Looper::template ConvertBasicType<From,Long_t>::Action, conf ); break;
2656  case TStreamerInfo::kLong64: return TConfiguredAction( Looper::template ConvertBasicType<From,Long64_t>::Action, conf ); break;
2657  case TStreamerInfo::kFloat: return TConfiguredAction( Looper::template ConvertBasicType<From,float>::Action, conf ); break;
2658  case TStreamerInfo::kFloat16: return TConfiguredAction( Looper::template ConvertBasicType<From,float>::Action, conf ); break;
2659  case TStreamerInfo::kDouble: return TConfiguredAction( Looper::template ConvertBasicType<From,double>::Action, conf ); break;
2660  case TStreamerInfo::kDouble32:return TConfiguredAction( Looper::template ConvertBasicType<From,double>::Action, conf ); break;
2661  case TStreamerInfo::kUChar: return TConfiguredAction( Looper::template ConvertBasicType<From,UChar_t>::Action, conf ); break;
2662  case TStreamerInfo::kUShort: return TConfiguredAction( Looper::template ConvertBasicType<From,UShort_t>::Action, conf ); break;
2663  case TStreamerInfo::kUInt: return TConfiguredAction( Looper::template ConvertBasicType<From,UInt_t>::Action, conf ); break;
2664  case TStreamerInfo::kULong: return TConfiguredAction( Looper::template ConvertBasicType<From,ULong_t>::Action, conf ); break;
2665  case TStreamerInfo::kULong64: return TConfiguredAction( Looper::template ConvertBasicType<From,ULong64_t>::Action, conf ); break;
2666  case TStreamerInfo::kBits: return TConfiguredAction( Looper::template ConvertBasicType<From,UInt_t>::Action, conf ); break;
2667  default:
2668  return TConfiguredAction( Looper::GenericRead, conf );
2669  break;
2670  }
2671  R__ASSERT(0); // We should never be here
2672  return TConfiguredAction();
2673 }
2674 
2675 template <class Looper>
2676 static TConfiguredAction GetNumericCollectionReadAction(Int_t type, TConfigSTL *conf)
2677 {
2678  // If we ever support std::vector<Double32_t> fValues; //[...] we would get the info from the StreamerElement for fValues.
2679 
2680  switch (type) {
2681  // Read basic types.
2682  case TStreamerInfo::kBool: return TConfiguredAction( Looper::ReadCollectionBool, conf ); break;
2683  case TStreamerInfo::kChar: return TConfiguredAction( Looper::template ReadCollectionBasicType<Char_t>, conf ); break;
2684  case TStreamerInfo::kShort: return TConfiguredAction( Looper::template ReadCollectionBasicType<Short_t>,conf ); break;
2685  case TStreamerInfo::kInt: return TConfiguredAction( Looper::template ReadCollectionBasicType<Int_t>, conf ); break;
2686  case TStreamerInfo::kLong: return TConfiguredAction( Looper::template ReadCollectionBasicType<Long_t>, conf ); break;
2687  case TStreamerInfo::kLong64: return TConfiguredAction( Looper::template ReadCollectionBasicType<Long64_t>, conf ); break;
2688  case TStreamerInfo::kFloat: return TConfiguredAction( Looper::template ReadCollectionBasicType<Float_t>, conf ); break;
2689  case TStreamerInfo::kDouble: return TConfiguredAction( Looper::template ReadCollectionBasicType<Double_t>, conf ); break;
2690  case TStreamerInfo::kUChar: return TConfiguredAction( Looper::template ReadCollectionBasicType<UChar_t>, conf ); break;
2691  case TStreamerInfo::kUShort: return TConfiguredAction( Looper::template ReadCollectionBasicType<UShort_t>, conf ); break;
2692  case TStreamerInfo::kUInt: return TConfiguredAction( Looper::template ReadCollectionBasicType<UInt_t>, conf ); break;
2693  case TStreamerInfo::kULong: return TConfiguredAction( Looper::template ReadCollectionBasicType<ULong_t>, conf ); break;
2694  case TStreamerInfo::kULong64: return TConfiguredAction( Looper::template ReadCollectionBasicType<ULong64_t>, conf ); break;
2695  case TStreamerInfo::kBits: Error("GetNumericCollectionReadAction","There is no support for kBits outside of a TObject."); break;
2696  case TStreamerInfo::kFloat16: {
2697  TConfigSTL *alternate = new TConfSTLNoFactor(conf,12);
2698  delete conf;
2699  return TConfiguredAction( Looper::ReadCollectionFloat16, alternate );
2700  // if (element->GetFactor() != 0) {
2701  // return TConfiguredAction( Looper::template ReadAction<ReadBasicType_WithFactor<float> >, new TConfWithFactor(info,i,compinfo,offset,element->GetFactor(),element->GetXmin()) );
2702  // } else {
2703  // Int_t nbits = (Int_t)element->GetXmin();
2704  // if (!nbits) nbits = 12;
2705  // return TConfiguredAction( Looper::template ReadAction<ReadBasicType_NoFactor<float> >, new TConfNoFactor(info,i,compinfo,offset,nbits) );
2706  // }
2707  break;
2708  }
2709  case TStreamerInfo::kDouble32: {
2710  TConfigSTL *alternate = new TConfSTLNoFactor(conf,0);
2711  delete conf;
2712  return TConfiguredAction( Looper::ReadCollectionDouble32, alternate );
2713  // if (element->GetFactor() != 0) {
2714  // return TConfiguredAction( Looper::template ReadAction<ReadBasicType_WithFactor<double> >, new TConfWithFactor(info,i,compinfo,offset,element->GetFactor(),element->GetXmin()) );
2715  // } else {
2716  // Int_t nbits = (Int_t)element->GetXmin();
2717  // if (!nbits) {
2718  // return TConfiguredAction( Looper::template ReadAction<ConvertBasicType<float,double> >, new TConfiguration(info,i,compinfo,offset) );
2719  // } else {
2720  // return TConfiguredAction( Looper::template ReadAction<ReadBasicType_NoFactor<double> >, new TConfNoFactor(info,i,compinfo,offset,nbits) );
2721  // }
2722  // }
2723  break;
2724  }
2725  }
2726  Fatal("GetNumericCollectionReadAction","Is confused about %d",type);
2727  R__ASSERT(0); // We should never be here
2728  return TConfiguredAction();
2729 }
2730 
2731 template <typename Looper, typename From>
2732 static TConfiguredAction GetConvertCollectionReadActionFrom(Int_t newtype, TConfiguration *conf)
2733 {
2734  switch (newtype) {
2735  case TStreamerInfo::kBool: return TConfiguredAction( Looper::template ConvertCollectionBasicType<From,bool>::Action, conf ); break;
2736  case TStreamerInfo::kChar: return TConfiguredAction( Looper::template ConvertCollectionBasicType<From,char>::Action, conf ); break;
2737  case TStreamerInfo::kShort: return TConfiguredAction( Looper::template ConvertCollectionBasicType<From,short>::Action, conf ); break;
2738  case TStreamerInfo::kInt: return TConfiguredAction( Looper::template ConvertCollectionBasicType<From,Int_t>::Action, conf ); break;
2739  case TStreamerInfo::kLong: return TConfiguredAction( Looper::template ConvertCollectionBasicType<From,Long_t>::Action, conf ); break;
2740  case TStreamerInfo::kLong64: return TConfiguredAction( Looper::template ConvertCollectionBasicType<From,Long64_t>::Action, conf ); break;
2741  case TStreamerInfo::kFloat: return TConfiguredAction( Looper::template ConvertCollectionBasicType<From,float>::Action, conf ); break;
2742  case TStreamerInfo::kFloat16: return TConfiguredAction( Looper::template ConvertCollectionBasicType<From,float>::Action, conf ); break;
2743  case TStreamerInfo::kDouble: return TConfiguredAction( Looper::template ConvertCollectionBasicType<From,double>::Action, conf ); break;
2744  case TStreamerInfo::kDouble32:return TConfiguredAction( Looper::template ConvertCollectionBasicType<From,double>::Action, conf ); break;
2745  case TStreamerInfo::kUChar: return TConfiguredAction( Looper::template ConvertCollectionBasicType<From,UChar_t>::Action, conf ); break;
2746  case TStreamerInfo::kUShort: return TConfiguredAction( Looper::template ConvertCollectionBasicType<From,UShort_t>::Action, conf ); break;
2747  case TStreamerInfo::kUInt: return TConfiguredAction( Looper::template ConvertCollectionBasicType<From,UInt_t>::Action, conf ); break;
2748  case TStreamerInfo::kULong: return TConfiguredAction( Looper::template ConvertCollectionBasicType<From,ULong_t>::Action, conf ); break;
2749  case TStreamerInfo::kULong64: return TConfiguredAction( Looper::template ConvertCollectionBasicType<From,ULong64_t>::Action, conf ); break;
2750  case TStreamerInfo::kBits: return TConfiguredAction( Looper::template ConvertCollectionBasicType<From,UInt_t>::Action, conf ); break;
2751  default:
2752  break;
2753  }
2754  R__ASSERT(0); // We should never be here
2755  return TConfiguredAction();
2756 }
2757 
2758 template <typename Looper>
2759 static TConfiguredAction GetConvertCollectionReadAction(Int_t oldtype, Int_t newtype, TConfiguration *conf)
2760 {
2761  switch (oldtype) {
2762  case TStreamerInfo::kBool:
2763  return GetConvertCollectionReadActionFrom<Looper,Bool_t>(newtype, conf );
2764  break;
2765  case TStreamerInfo::kChar:
2766  return GetConvertCollectionReadActionFrom<Looper,Char_t>(newtype, conf );
2767  break;
2768  case TStreamerInfo::kShort:
2769  return GetConvertCollectionReadActionFrom<Looper,Short_t>(newtype, conf );
2770  break;
2771  case TStreamerInfo::kInt:
2772  return GetConvertCollectionReadActionFrom<Looper,Int_t>(newtype, conf );
2773  break;
2774  case TStreamerInfo::kLong:
2775  return GetConvertCollectionReadActionFrom<Looper,Long_t>(newtype, conf );
2776  break;
2777  case TStreamerInfo::kLong64:
2778  return GetConvertCollectionReadActionFrom<Looper,Long64_t>(newtype, conf );
2779  break;
2780  case TStreamerInfo::kFloat:
2781  return GetConvertCollectionReadActionFrom<Looper,Float_t>( newtype, conf );
2782  break;
2783  case TStreamerInfo::kDouble:
2784  return GetConvertCollectionReadActionFrom<Looper,Double_t>(newtype, conf );
2785  break;
2786  case TStreamerInfo::kUChar:
2787  return GetConvertCollectionReadActionFrom<Looper,UChar_t>(newtype, conf );
2788  break;
2789  case TStreamerInfo::kUShort:
2790  return GetConvertCollectionReadActionFrom<Looper,UShort_t>(newtype, conf );
2791  break;
2792  case TStreamerInfo::kUInt:
2793  return GetConvertCollectionReadActionFrom<Looper,UInt_t>(newtype, conf );
2794  break;
2795  case TStreamerInfo::kULong:
2796  return GetConvertCollectionReadActionFrom<Looper,ULong_t>(newtype, conf );
2797  break;
2798  case TStreamerInfo::kULong64:
2799  return GetConvertCollectionReadActionFrom<Looper,ULong64_t>(newtype, conf );
2800  break;
2801  case TStreamerInfo::kFloat16:
2802  return GetConvertCollectionReadActionFrom<Looper,NoFactorMarker<Float16_t> >( newtype, conf );
2803  break;
2804  case TStreamerInfo::kDouble32:
2805  return GetConvertCollectionReadActionFrom<Looper,NoFactorMarker<Double32_t> >( newtype, conf );
2806  break;
2807  case TStreamerInfo::kBits:
2808  Error("GetConvertCollectionReadAction","There is no support for kBits outside of a TObject.");
2809  break;
2810  default:
2811  break;
2812  }
2813  R__ASSERT(0); // We should never be here
2814  return TConfiguredAction();
2815 }
2816 
2817 template <class Looper>
2818 static TConfiguredAction GetCollectionReadAction(TVirtualStreamerInfo *info, TStreamerElement *element, Int_t type, UInt_t i, TStreamerInfo::TCompInfo_t *compinfo, Int_t offset)
2819 {
2820  switch (type) {
2821  // Read basic types.
2822  case TStreamerInfo::kBool: return TConfiguredAction( Looper::template ReadBasicType<Bool_t>, new TConfiguration(info,i,compinfo,offset) ); break;
2823  case TStreamerInfo::kChar: return TConfiguredAction( Looper::template ReadBasicType<Char_t>, new TConfiguration(info,i,compinfo,offset) ); break;
2824  case TStreamerInfo::kShort: return TConfiguredAction( Looper::template ReadBasicType<Short_t>,new TConfiguration(info,i,compinfo,offset) ); break;
2825  case TStreamerInfo::kInt: return TConfiguredAction( Looper::template ReadBasicType<Int_t>, new TConfiguration(info,i,compinfo,offset) ); break;
2826  case TStreamerInfo::kLong: return TConfiguredAction( Looper::template ReadBasicType<Long_t>, new TConfiguration(info,i,compinfo,offset) ); break;
2827  case TStreamerInfo::kLong64: return TConfiguredAction( Looper::template ReadBasicType<Long64_t>, new TConfiguration(info,i,compinfo,offset) ); break;
2828  case TStreamerInfo::kFloat: return TConfiguredAction( Looper::template ReadBasicType<Float_t>, new TConfiguration(info,i,compinfo,offset) ); break;
2829  case TStreamerInfo::kDouble: return TConfiguredAction( Looper::template ReadBasicType<Double_t>, new TConfiguration(info,i,compinfo,offset) ); break;
2830  case TStreamerInfo::kUChar: return TConfiguredAction( Looper::template ReadBasicType<UChar_t>, new TConfiguration(info,i,compinfo,offset) ); break;
2831  case TStreamerInfo::kUShort: return TConfiguredAction( Looper::template ReadBasicType<UShort_t>, new TConfiguration(info,i,compinfo,offset) ); break;
2832  case TStreamerInfo::kUInt: return TConfiguredAction( Looper::template ReadBasicType<UInt_t>, new TConfiguration(info,i,compinfo,offset) ); break;
2833  case TStreamerInfo::kULong: return TConfiguredAction( Looper::template ReadBasicType<ULong_t>, new TConfiguration(info,i,compinfo,offset) ); break;
2834  case TStreamerInfo::kULong64: return TConfiguredAction( Looper::template ReadBasicType<ULong64_t>, new TConfiguration(info,i,compinfo,offset) ); break;
2835  case TStreamerInfo::kBits: return TConfiguredAction( Looper::template ReadAction<TStreamerInfoActions::ReadBasicType<BitsMarker> > , new TBitsConfiguration(info,i,compinfo,offset) ); break;
2836  case TStreamerInfo::kFloat16: {
2837  if (element->GetFactor() != 0) {
2838  return TConfiguredAction( Looper::template ReadAction<ReadBasicType_WithFactor<float> >, new TConfWithFactor(info,i,compinfo,offset,element->GetFactor(),element->GetXmin()) );
2839  } else {
2840  Int_t nbits = (Int_t)element->GetXmin();
2841  if (!nbits) nbits = 12;
2842  return TConfiguredAction( Looper::template ReadAction<ReadBasicType_NoFactor<float> >, new TConfNoFactor(info,i,compinfo,offset,nbits) );
2843  }
2844  break;
2845  }
2846  case TStreamerInfo::kDouble32: {
2847  if (element->GetFactor() != 0) {
2848  return TConfiguredAction( Looper::template ReadAction<ReadBasicType_WithFactor<double> >, new TConfWithFactor(info,i,compinfo,offset,element->GetFactor(),element->GetXmin()) );
2849  } else {
2850  Int_t nbits = (Int_t)element->GetXmin();
2851  if (!nbits) {
2852  return TConfiguredAction( Looper::template ReadAction<ConvertBasicType<float,double>::Action >, new TConfiguration(info,i,compinfo,offset) );
2853  } else {
2854  return TConfiguredAction( Looper::template ReadAction<ReadBasicType_NoFactor<double> >, new TConfNoFactor(info,i,compinfo,offset,nbits) );
2855  }
2856  }
2857  break;
2858  }
2859  case TStreamerInfo::kTNamed: return TConfiguredAction( Looper::template ReadAction<ReadTNamed >, new TConfiguration(info,i,compinfo,offset) ); break;
2860  // Idea: We should calculate the CanIgnoreTObjectStreamer here and avoid calling the
2861  // Streamer alltogether.
2862  case TStreamerInfo::kTObject: return TConfiguredAction( Looper::template ReadAction<ReadTObject >, new TConfiguration(info,i,compinfo,offset) ); break;
2863  case TStreamerInfo::kTString: return TConfiguredAction( Looper::template ReadAction<ReadTString >, new TConfiguration(info,i,compinfo,offset) ); break;
2864  case TStreamerInfo::kArtificial:
2865  case TStreamerInfo::kCacheNew:
2866  case TStreamerInfo::kCacheDelete:
2867  case TStreamerInfo::kSTL: return TConfiguredAction( Looper::GenericRead, new TGenericConfiguration(info,i,compinfo) ); break;
2868  case TStreamerInfo::kBase: return TConfiguredAction( Looper::ReadBase, new TGenericConfiguration(info,i,compinfo) ); break;
2869 
2870  // Conversions.
2871  case TStreamerInfo::kConv + TStreamerInfo::kBool:
2872  return GetCollectionReadConvertAction<Looper,Bool_t>(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) );
2873  break;
2874  case TStreamerInfo::kConv + TStreamerInfo::kChar:
2875  return GetCollectionReadConvertAction<Looper,Char_t>(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) );
2876  break;
2877  case TStreamerInfo::kConv + TStreamerInfo::kShort:
2878  return GetCollectionReadConvertAction<Looper,Short_t>(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) );
2879  break;
2880  case TStreamerInfo::kConv + TStreamerInfo::kInt:
2881  return GetCollectionReadConvertAction<Looper,Int_t>(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) );
2882  break;
2883  case TStreamerInfo::kConv + TStreamerInfo::kLong:
2884  return GetCollectionReadConvertAction<Looper,Long_t>(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) );
2885  break;
2886  case TStreamerInfo::kConv + TStreamerInfo::kLong64:
2887  return GetCollectionReadConvertAction<Looper,Long64_t>(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) );
2888  break;
2889  case TStreamerInfo::kConv + TStreamerInfo::kFloat:
2890  return GetCollectionReadConvertAction<Looper,Float_t>( element->GetNewType(), new TConfiguration(info,i,compinfo,offset) );
2891  break;
2892  case TStreamerInfo::kConv + TStreamerInfo::kDouble:
2893  return GetCollectionReadConvertAction<Looper,Double_t>(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) );
2894  break;
2895  case TStreamerInfo::kConv + TStreamerInfo::kUChar:
2896  return GetCollectionReadConvertAction<Looper,UChar_t>(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) );
2897  break;
2898  case TStreamerInfo::kConv + TStreamerInfo::kUShort:
2899  return GetCollectionReadConvertAction<Looper,UShort_t>(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) );
2900  break;
2901  case TStreamerInfo::kConv + TStreamerInfo::kUInt:
2902  return GetCollectionReadConvertAction<Looper,UInt_t>(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) );
2903  break;
2904  case TStreamerInfo::kConv + TStreamerInfo::kULong:
2905  return GetCollectionReadConvertAction<Looper,ULong_t>(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) );
2906  break;
2907  case TStreamerInfo::kConv + TStreamerInfo::kULong64:
2908  return GetCollectionReadConvertAction<Looper,ULong64_t>(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) );
2909  break;
2910  case TStreamerInfo::kConv + TStreamerInfo::kBits:
2911  return GetCollectionReadConvertAction<Looper,BitsMarker>(element->GetNewType(), new TBitsConfiguration(info,i,compinfo,offset) );
2912  break;
2913  case TStreamerInfo::kConv + TStreamerInfo::kFloat16: {
2914  if (element->GetFactor() != 0) {
2915  return GetCollectionReadConvertAction<Looper,WithFactorMarker<float> >(element->GetNewType(), new TConfWithFactor(info,i,compinfo,offset,element->GetFactor(),element->GetXmin()) );
2916  } else {
2917  Int_t nbits = (Int_t)element->GetXmin();
2918  if (!nbits) nbits = 12;
2919  return GetCollectionReadConvertAction<Looper,NoFactorMarker<float> >(element->GetNewType(), new TConfNoFactor(info,i,compinfo,offset,nbits) );
2920  }
2921  break;
2922  }
2923  case TStreamerInfo::kConv + TStreamerInfo::kDouble32: {
2924  if (element->GetFactor() != 0) {
2925  return GetCollectionReadConvertAction<Looper,WithFactorMarker<double> >(element->GetNewType(), new TConfWithFactor(info,i,compinfo,offset,element->GetFactor(),element->GetXmin()) );
2926  } else {
2927  Int_t nbits = (Int_t)element->GetXmin();
2928  if (!nbits) {
2929  return GetCollectionReadConvertAction<Looper,Float_t>(element->GetNewType(), new TConfiguration(info,i,compinfo,offset) );
2930  } else {
2931  return GetCollectionReadConvertAction<Looper,NoFactorMarker<double> >(element->GetNewType(), new TConfNoFactor(info,i,compinfo,offset,nbits) );
2932  }
2933  }
2934  break;
2935  }
2936  default:
2937  return TConfiguredAction( Looper::GenericRead, new TGenericConfiguration(info,i,compinfo) );
2938  break;
2939  }
2940  R__ASSERT(0); // We should never be here
2941  return TConfiguredAction();
2942 }
2943 
2944 template <class Looper>
2945 static TConfiguredAction GetCollectionWriteAction(TVirtualStreamerInfo *info, TStreamerElement * /*element*/, Int_t type, UInt_t i, TStreamerInfo::TCompInfo_t *compinfo, Int_t offset) {
2946  switch (type) {
2947  // read basic types
2948  case TStreamerInfo::kBool: return TConfiguredAction( Looper::template WriteBasicType<Bool_t>, new TConfiguration(info,i,compinfo,offset) ); break;
2949  case TStreamerInfo::kChar: return TConfiguredAction( Looper::template WriteBasicType<Char_t>, new TConfiguration(info,i,compinfo,offset) ); break;
2950  case TStreamerInfo::kShort: return TConfiguredAction( Looper::template WriteBasicType<Short_t>, new TConfiguration(info,i,compinfo,offset) ); break;
2951  case TStreamerInfo::kInt: return TConfiguredAction( Looper::template WriteBasicType<Int_t>, new TConfiguration(info,i,compinfo,offset) ); break;
2952  case TStreamerInfo::kLong: return TConfiguredAction( Looper::template WriteBasicType<Long_t>, new TConfiguration(info,i,compinfo,offset) ); break;
2953  case TStreamerInfo::kLong64: return TConfiguredAction( Looper::template WriteBasicType<Long64_t>, new TConfiguration(info,i,compinfo,offset) ); break;
2954  case TStreamerInfo::kFloat: return TConfiguredAction( Looper::template WriteBasicType<Float_t>, new TConfiguration(info,i,compinfo,offset) ); break;
2955  case TStreamerInfo::kDouble: return TConfiguredAction( Looper::template WriteBasicType<Double_t>, new TConfiguration(info,i,compinfo,offset) ); break;
2956  case TStreamerInfo::kUChar: return TConfiguredAction( Looper::template WriteBasicType<UChar_t>, new TConfiguration(info,i,compinfo,offset) ); break;
2957  case TStreamerInfo::kUShort: return TConfiguredAction( Looper::template WriteBasicType<UShort_t>, new TConfiguration(info,i,compinfo,offset) ); break;
2958  case TStreamerInfo::kUInt: return TConfiguredAction( Looper::template WriteBasicType<UInt_t>, new TConfiguration(info,i,compinfo,offset) ); break;
2959  case TStreamerInfo::kULong: return TConfiguredAction( Looper::template WriteBasicType<ULong_t>, new TConfiguration(info,i,compinfo,offset) ); break;
2960  case TStreamerInfo::kULong64: return TConfiguredAction( Looper::template WriteBasicType<ULong64_t>,new TConfiguration(info,i,compinfo,offset) ); break;
2961  // the simple type missing are kBits and kCounter.
2962  default:
2963  return TConfiguredAction( Looper::GenericWrite, new TConfiguration(info,i,compinfo,0 /* 0 because we call the legacy code */) );
2964  }
2965  R__ASSERT(0); // We should never be here
2966  return TConfiguredAction();
2967 }
2968 
2969 
2970 ////////////////////////////////////////////////////////////////////////////////
2971 /// loop on the TStreamerElement list
2972 /// regroup members with same type
2973 /// Store predigested information into local arrays. This saves a huge amount
2974 /// of time compared to an explicit iteration on all elements.
2975 
2976 void TStreamerInfo::Compile()
2977 {
2978  if (IsCompiled()) {
2979  //Error("Compile","can only be called once; this first call generates both the optimized and memberwise actions.");
2980  return;
2981  }
2982  R__LOCKGUARD(gInterpreterMutex);
2983 
2984  // fprintf(stderr,"Running Compile for %s %d %d req=%d,%d\n",GetName(),fClassVersion,fOptimized,CanOptimize(),TestBit(kCannotOptimize));
2985 
2986  // if (IsCompiled() && (!fOptimized || (CanOptimize() && !TestBit(kCannotOptimize)))) return;
2987  fOptimized = kFALSE;
2988  fNdata = 0;
2989  fNfulldata = 0;
2990 
2991  TObjArray* infos = (TObjArray*) gROOT->GetListOfStreamerInfo();
2992  if (fNumber < 0) {
2993  ++fgCount;
2994  fNumber = fgCount;
2995  }
2996  if (fNumber >= infos->GetSize()) {
2997  infos->AddAtAndExpand(this, fNumber);
2998  } else {
2999  if (!infos->At(fNumber)) {
3000  infos->AddAt(this, fNumber);
3001  }
3002  }
3003 
3004  assert(fComp == 0 && fCompFull == 0 && fCompOpt == 0);
3005 
3006 
3007  Int_t ndata = fElements->GetEntries();
3008 
3009 
3010  if (fReadObjectWise) fReadObjectWise->fActions.clear();
3011  else fReadObjectWise = new TStreamerInfoActions::TActionSequence(this,ndata);
3012 
3013  if (fWriteObjectWise) fWriteObjectWise->fActions.clear();
3014  else fWriteObjectWise = new TStreamerInfoActions::TActionSequence(this,ndata);
3015 
3016  if (fReadMemberWise) fReadMemberWise->fActions.clear();
3017  else fReadMemberWise = new TStreamerInfoActions::TActionSequence(this,ndata);
3018 
3019  if (fReadText) fReadText->fActions.clear();
3020  else fReadText = new TStreamerInfoActions::TActionSequence(this,ndata);
3021 
3022  if (fWriteMemberWise) fWriteMemberWise->fActions.clear();
3023  else fWriteMemberWise = new TStreamerInfoActions::TActionSequence(this,ndata);
3024 
3025  if (fReadMemberWiseVecPtr) fReadMemberWiseVecPtr->fActions.clear();
3026  else fReadMemberWiseVecPtr = new TStreamerInfoActions::TActionSequence(this,ndata);
3027 
3028  if (fWriteMemberWiseVecPtr) fWriteMemberWiseVecPtr->fActions.clear();
3029  else fWriteMemberWiseVecPtr = new TStreamerInfoActions::TActionSequence(this,ndata);
3030 
3031  if (fWriteText) fWriteText->fActions.clear();
3032  else fWriteText = new TStreamerInfoActions::TActionSequence(this,ndata);
3033 
3034  if (!ndata) {
3035  // This may be the case for empty classes (e.g., TAtt3D).
3036  // We still need to properly set the size of emulated classes (i.e. add the virtual table)
3037  if (fClass->TestBit(TClass::kIsEmulation) && fNVirtualInfoLoc!=0) {
3038  fSize = sizeof(TStreamerInfo*);
3039  }
3040  fComp = new TCompInfo[1];
3041  fCompFull = new TCompInfo*[1];
3042  fCompOpt = new TCompInfo*[1];
3043  fCompOpt[0] = fCompFull[0] = &(fComp[0]);
3044  SetIsCompiled();
3045  return;
3046  }
3047 
3048  // At most half of the elements can be used to hold optimized versions.
3049  // We use the bottom to hold the optimized-into elements and the non-optimized elements
3050  // and the top to hold the original copy of the optimized out elements.
3051  fNslots = ndata + ndata/2 + 1;
3052  Int_t optiOut = 0;
3053 
3054  fComp = new TCompInfo[fNslots];
3055  fCompFull = new TCompInfo*[ndata];
3056  fCompOpt = new TCompInfo*[ndata];
3057 
3058  TStreamerElement* element;
3059  TStreamerElement* previous = 0;
3060  Int_t keep = -1;
3061  Int_t i;
3062 
3063  if (!CanOptimize()) {
3064  SetBit(kCannotOptimize);
3065  }
3066 
3067  Bool_t isOptimized = kFALSE;
3068  Bool_t previousOptimized = kFALSE;
3069 
3070  for (i = 0; i < ndata; ++i) {
3071  element = (TStreamerElement*) fElements->At(i);
3072  if (!element) {
3073  break;
3074  }
3075 
3076  Int_t asize = element->GetSize();
3077  if (element->GetArrayLength()) {
3078  asize /= element->GetArrayLength();
3079  }
3080  fComp[fNdata].fType = element->GetType();
3081  fComp[fNdata].fNewType = element->GetNewType();
3082  fComp[fNdata].fOffset = element->GetOffset();
3083  fComp[fNdata].fLength = element->GetArrayLength();
3084  fComp[fNdata].fElem = element;
3085  fComp[fNdata].fMethod = element->GetMethod();
3086  fComp[fNdata].fClass = element->GetClassPointer();
3087  fComp[fNdata].fNewClass = element->GetNewClass();
3088  fComp[fNdata].fClassName = TString(element->GetTypeName()).Strip(TString::kTrailing, '*');
3089  fComp[fNdata].fStreamer = element->GetStreamer();
3090 
3091  // try to group consecutive members of the same type
3092  if (!TestBit(kCannotOptimize)
3093  && (keep >= 0)
3094  && (element->GetType() > 0)
3095  && (element->GetType() < 10)
3096  && (fComp[fNdata].fType == fComp[fNdata].fNewType)
3097  && (fComp[keep].fMethod == 0)
3098  && (element->GetArrayDim() == 0)
3099  && (fComp[keep].fType < kObject)
3100  && (fComp[keep].fType != kCharStar) /* do not optimize char* */
3101  && (element->GetType() == (fComp[keep].fType%kRegrouped))
3102  && ((element->GetOffset()-fComp[keep].fOffset) == (fComp[keep].fLength)*asize)
3103  && ((fOldVersion<6) || !previous || /* In version of TStreamerInfo less than 6, the Double32_t were merged even if their annotation (aka factor) were different */
3104  ((element->GetFactor() == previous->GetFactor())
3105  && (element->GetXmin() == previous->GetXmin())
3106  && (element->GetXmax() == previous->GetXmax())
3107  )
3108  )
3109  && (element->TestBit(TStreamerElement::kCache) == previous->TestBit(TStreamerElement::kCache))
3110  && (element->TestBit(TStreamerElement::kWrite) == previous->TestBit(TStreamerElement::kWrite))
3111  // kWholeObject and kDoNotDelete do not apply to numerical elements.
3112  )
3113  {
3114  if (!previousOptimized) {
3115  // The element was not yet optimized we first need to copy it into
3116  // the set of original copies.
3117  fComp[fNslots - (++optiOut) ] = fComp[keep]; // Copy the optimized out elements.
3118  fCompFull[fNfulldata-1] = &(fComp[fNslots - optiOut]); // Reset the pointer in the full list.
3119  }
3120  fComp[fNslots - (++optiOut) ] = fComp[fNdata]; // Copy the optimized out elements.
3121  fCompFull[fNfulldata] = &(fComp[fNslots - optiOut]);
3122 
3123  R__ASSERT( keep < (fNslots - optiOut) );
3124 
3125  if (fComp[keep].fLength == 0) {
3126  fComp[keep].fLength++;
3127  }
3128  fComp[keep].fLength++;
3129  fComp[keep].fType = element->GetType() + kRegrouped;
3130  isOptimized = kTRUE;
3131  previousOptimized = kTRUE;
3132  } else if (element->GetType() < 0) {
3133 
3134  // -- Deal with an ignored TObject base class.
3135  // Note: The only allowed negative value here is -1,
3136  // and signifies that Build() has found a TObject
3137  // base class and TClass::IgnoreTObjectStreamer() was
3138  // called. In this case the compiled version of the
3139  // elements omits the TObject base class element,
3140  // which has to be compensated for by TTree::Bronch()
3141  // when it is making branches for a split object.
3142  fComp[fNslots - (++optiOut) ] = fComp[fNdata]; // Copy the 'ignored' element.
3143  fCompFull[fNfulldata] = &(fComp[fNslots - optiOut]);
3144  keep = -1;
3145  previousOptimized = kFALSE;
3146 
3147  } else {
3148  if (fComp[fNdata].fNewType != fComp[fNdata].fType) {
3149  if (fComp[fNdata].fNewType > 0) {
3150  if ( (fComp[fNdata].fNewType == kObjectp || fComp[fNdata].fNewType == kAnyp
3151  || fComp[fNdata].fNewType == kObject || fComp[fNdata].fNewType == kAny
3152  || fComp[fNdata].fNewType == kTObject || fComp[fNdata].fNewType == kTNamed || fComp[fNdata].fNewType == kTString)
3153  && (fComp[fNdata].fType == kObjectp || fComp[fNdata].fType == kAnyp
3154  || fComp[fNdata].fType == kObject || fComp[fNdata].fType == kAny
3155  || fComp[fNdata].fType == kTObject || fComp[fNdata].fType == kTNamed || fComp[fNdata].fType == kTString )
3156  ) {
3157  fComp[fNdata].fType = fComp[fNdata].fNewType;
3158  } else if (fComp[fNdata].fType != kCounter) {
3159  fComp[fNdata].fType += kConv;
3160  }
3161  } else {
3162  if (fComp[fNdata].fType == kCounter) {
3163  Warning("Compile", "Counter %s should not be skipped from class %s", element->GetName(), GetName());
3164  }
3165  fComp[fNdata].fType += kSkip;
3166  }
3167  }
3168  fCompOpt[fNdata] = &(fComp[fNdata]);
3169  fCompFull[fNfulldata] = &(fComp[fNdata]);
3170 
3171  R__ASSERT( fNdata < (fNslots - optiOut) );
3172 
3173  keep = fNdata;
3174  if (fComp[keep].fLength == 0) {
3175  fComp[keep].fLength = 1;
3176  }
3177  fNdata++;
3178  previousOptimized = kFALSE;
3179  }
3180  // The test 'fMethod[keep] == 0' fails to detect a variable size array
3181  // if the counter happens to have an offset of zero, so let's explicitly
3182  // prevent for here.
3183  if (element->HasCounter()) keep = -1;
3184  ++fNfulldata;
3185  previous = element;
3186  }
3187 
3188  for (i = 0; i < fNdata; ++i) {
3189  if (!fCompOpt[i]->fElem || fCompOpt[i]->fElem->GetType()< 0) {
3190  continue;
3191  }
3192  AddReadAction(fReadObjectWise, i, fCompOpt[i]);
3193  AddWriteAction(fWriteObjectWise, i, fCompOpt[i]);
3194  }
3195  for (i = 0; i < fNfulldata; ++i) {
3196  if (!fCompFull[i]->fElem || fCompFull[i]->fElem->GetType()< 0) {
3197  continue;
3198  }
3199  AddReadAction(fReadMemberWise, i, fCompFull[i]);
3200  AddWriteAction(fWriteMemberWise, i, fCompFull[i]);
3201  AddReadMemberWiseVecPtrAction(fReadMemberWiseVecPtr, i, fCompFull[i]);
3202  AddWriteMemberWiseVecPtrAction(fWriteMemberWiseVecPtr, i, fCompFull[i]);
3203 
3204  AddReadTextAction(fReadText, i, fCompFull[i]);
3205  AddWriteTextAction(fWriteText, i, fCompFull[i]);
3206  }
3207  ComputeSize();
3208 
3209  fOptimized = isOptimized;
3210  SetIsCompiled();
3211 
3212  if (gDebug > 0) {
3213  ls();
3214  }
3215 }
3216 
3217 template <typename From>
3218 static void AddReadConvertAction(TStreamerInfoActions::TActionSequence *sequence, Int_t newtype, TConfiguration *conf)
3219 {
3220  switch (newtype) {
3221  case TStreamerInfo::kBool: sequence->AddAction( ConvertBasicType<From,bool>::Action, conf ); break;
3222  case TStreamerInfo::kChar: sequence->AddAction( ConvertBasicType<From,char>::Action, conf ); break;
3223  case TStreamerInfo::kShort: sequence->AddAction( ConvertBasicType<From,short>::Action, conf ); break;
3224  case TStreamerInfo::kInt: sequence->AddAction( ConvertBasicType<From,Int_t>::Action, conf ); break;
3225  case TStreamerInfo::kLong: sequence->AddAction( ConvertBasicType<From,Long_t>::Action,conf ); break;
3226  case TStreamerInfo::kLong64: sequence->AddAction( ConvertBasicType<From,Long64_t>::Action, conf ); break;
3227  case TStreamerInfo::kFloat: sequence->AddAction( ConvertBasicType<From,float>::Action, conf ); break;
3228  case TStreamerInfo::kFloat16: sequence->AddAction( ConvertBasicType<From,float>::Action, conf ); break;
3229  case TStreamerInfo::kDouble: sequence->AddAction( ConvertBasicType<From,double>::Action, conf ); break;
3230  case TStreamerInfo::kDouble32:sequence->AddAction( ConvertBasicType<From,double>::Action, conf ); break;
3231  case TStreamerInfo::kUChar: sequence->AddAction( ConvertBasicType<From,UChar_t>::Action, conf ); break;
3232  case TStreamerInfo::kUShort: sequence->AddAction( ConvertBasicType<From,UShort_t>::Action, conf ); break;
3233  case TStreamerInfo::kUInt: sequence->AddAction( ConvertBasicType<From,UInt_t>::Action, conf ); break;
3234  case TStreamerInfo::kULong: sequence->AddAction( ConvertBasicType<From,ULong_t>::Action, conf ); break;
3235  case TStreamerInfo::kULong64: sequence->AddAction( ConvertBasicType<From,ULong64_t>::Action,conf ); break;
3236  case TStreamerInfo::kBits: sequence->AddAction( ConvertBasicType<From,UInt_t>::Action, conf ); break;
3237  }
3238 }
3239 
3240 ////////////////////////////////////////////////////////////////////////////////
3241 /// Add a read action for the given element.
3242 
3243 void TStreamerInfo::AddReadAction(TStreamerInfoActions::TActionSequence *readSequence, Int_t i, TStreamerInfo::TCompInfo *compinfo)
3244 {
3245  TStreamerElement *element = compinfo->fElem;
3246 
3247  if (element->TestBit(TStreamerElement::kWrite)) return;
3248 
3249  switch (compinfo->fType) {
3250  // read basic types
3251  case TStreamerInfo::kBool: readSequence->AddAction( ReadBasicType<Bool_t>, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3252  case TStreamerInfo::kChar: readSequence->AddAction( ReadBasicType<Char_t>, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3253  case TStreamerInfo::kShort: readSequence->AddAction( ReadBasicType<Short_t>, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3254  case TStreamerInfo::kInt: readSequence->AddAction( ReadBasicType<Int_t>, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3255  case TStreamerInfo::kLong: readSequence->AddAction( ReadBasicType<Long_t>, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3256  case TStreamerInfo::kLong64: readSequence->AddAction( ReadBasicType<Long64_t>, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3257  case TStreamerInfo::kFloat: readSequence->AddAction( ReadBasicType<Float_t>, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3258  case TStreamerInfo::kDouble: readSequence->AddAction( ReadBasicType<Double_t>, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3259  case TStreamerInfo::kUChar: readSequence->AddAction( ReadBasicType<UChar_t>, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3260  case TStreamerInfo::kUShort: readSequence->AddAction( ReadBasicType<UShort_t>, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3261  case TStreamerInfo::kUInt: readSequence->AddAction( ReadBasicType<UInt_t>, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3262  case TStreamerInfo::kULong: readSequence->AddAction( ReadBasicType<ULong_t>, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3263  case TStreamerInfo::kULong64: readSequence->AddAction( ReadBasicType<ULong64_t>, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3264  case TStreamerInfo::kBits: readSequence->AddAction( ReadBasicType<BitsMarker>, new TBitsConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3265  case TStreamerInfo::kFloat16: {
3266  if (element->GetFactor() != 0) {
3267  readSequence->AddAction( ReadBasicType_WithFactor<float>, new TConfWithFactor(this,i,compinfo,compinfo->fOffset,element->GetFactor(),element->GetXmin()) );
3268  } else {
3269  Int_t nbits = (Int_t)element->GetXmin();
3270  if (!nbits) nbits = 12;
3271  readSequence->AddAction( ReadBasicType_NoFactor<float>, new TConfNoFactor(this,i,compinfo,compinfo->fOffset,nbits) );
3272  }
3273  break;
3274  }
3275  case TStreamerInfo::kDouble32: {
3276  if (element->GetFactor() != 0) {
3277  readSequence->AddAction( ReadBasicType_WithFactor<double>, new TConfWithFactor(this,i,compinfo,compinfo->fOffset,element->GetFactor(),element->GetXmin()) );
3278  } else {
3279  Int_t nbits = (Int_t)element->GetXmin();
3280  if (!nbits) {
3281  readSequence->AddAction( ConvertBasicType<float,double>::Action, new TConfiguration(this,i,compinfo,compinfo->fOffset) );
3282  } else {
3283  readSequence->AddAction( ReadBasicType_NoFactor<double>, new TConfNoFactor(this,i,compinfo,compinfo->fOffset,nbits) );
3284  }
3285  }
3286  break;
3287  }
3288  case TStreamerInfo::kTNamed: readSequence->AddAction( ReadTNamed, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3289  // Idea: We should calculate the CanIgnoreTObjectStreamer here and avoid calling the
3290  // Streamer alltogether.
3291  case TStreamerInfo::kTObject: readSequence->AddAction( ReadTObject, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3292  case TStreamerInfo::kTString: readSequence->AddAction( ReadTString, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3293  case TStreamerInfo::kSTL: {
3294  TClass *newClass = element->GetNewClass();
3295  TClass *oldClass = element->GetClassPointer();
3296  Bool_t isSTLbase = element->IsBase() && element->IsA()!=TStreamerBase::Class();
3297 
3298  if (element->GetArrayLength() <= 1) {
3299  if (fOldVersion<3){ // case of old TStreamerInfo
3300  if (newClass && newClass != oldClass) {
3301  if (element->GetStreamer()) {
3302  readSequence->AddAction(ReadSTL<ReadSTLMemberWiseChangedClass,ReadSTLObjectWiseStreamerV2>, new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetStreamer(),element->GetTypeName(),isSTLbase));
3303  } else {
3304  readSequence->AddAction(ReadSTL<ReadSTLMemberWiseChangedClass,ReadSTLObjectWiseFastArrayV2>, new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetTypeName(),isSTLbase));
3305  }
3306  } else {
3307  if (element->GetStreamer()) {
3308  readSequence->AddAction(ReadSTL<ReadSTLMemberWiseSameClass,ReadSTLObjectWiseStreamerV2>, new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetStreamer(),element->GetTypeName(),isSTLbase));
3309  } else {
3310  readSequence->AddAction(ReadSTL<ReadSTLMemberWiseSameClass,ReadSTLObjectWiseFastArrayV2>, new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetTypeName(),isSTLbase));
3311  }
3312  }
3313  } else {
3314  if (newClass && newClass != oldClass) {
3315  if (element->GetStreamer()) {
3316  readSequence->AddAction(ReadSTL<ReadSTLMemberWiseChangedClass,ReadSTLObjectWiseStreamer>, new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetStreamer(),element->GetTypeName(),isSTLbase));
3317  } else {
3318  if (oldClass->GetCollectionProxy() == 0 || oldClass->GetCollectionProxy()->GetValueClass() || oldClass->GetCollectionProxy()->HasPointers() ) {
3319  readSequence->AddAction(ReadSTL<ReadSTLMemberWiseChangedClass,ReadSTLObjectWiseFastArray>, new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetTypeName(),isSTLbase));
3320  } else {
3321  switch (SelectLooper(*newClass->GetCollectionProxy())) {
3322  case kVectorLooper:
3323  readSequence->AddAction(GetConvertCollectionReadAction<VectorLooper>(oldClass->GetCollectionProxy()->GetType(), newClass->GetCollectionProxy()->GetType(), new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetTypeName(),isSTLbase)));
3324  break;
3325  case kAssociativeLooper:
3326  readSequence->AddAction(GetConvertCollectionReadAction<AssociativeLooper>(oldClass->GetCollectionProxy()->GetType(), newClass->GetCollectionProxy()->GetType(), new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetTypeName(),isSTLbase)));
3327  break;
3328  case kVectorPtrLooper:
3329  case kGenericLooper:
3330  default:
3331  // For now TBufferXML would force use to allocate the data buffer each time and copy into the real thing.
3332  readSequence->AddAction(GetConvertCollectionReadAction<GenericLooper>(oldClass->GetCollectionProxy()->GetType(), newClass->GetCollectionProxy()->GetType(), new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetTypeName(),isSTLbase)));
3333  break;
3334  }
3335  }
3336  }
3337  } else {
3338  if (element->GetStreamer()) {
3339  readSequence->AddAction(ReadSTL<ReadSTLMemberWiseSameClass,ReadSTLObjectWiseStreamer>, new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetStreamer(),element->GetTypeName(),isSTLbase));
3340  } else {
3341  if (oldClass->GetCollectionProxy() == 0 || oldClass->GetCollectionProxy()->GetValueClass() || oldClass->GetCollectionProxy()->HasPointers() ) {
3342  readSequence->AddAction(ReadSTL<ReadSTLMemberWiseSameClass,ReadSTLObjectWiseFastArray>, new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetTypeName(),isSTLbase));
3343  } else {
3344  switch (SelectLooper(*oldClass->GetCollectionProxy())) {
3345  case kVectorLooper:
3346  readSequence->AddAction(GetNumericCollectionReadAction<VectorLooper>(oldClass->GetCollectionProxy()->GetType(), new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetTypeName(),isSTLbase)));
3347  break;
3348  case kAssociativeLooper:
3349  readSequence->AddAction(GetNumericCollectionReadAction<AssociativeLooper>(oldClass->GetCollectionProxy()->GetType(), new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetTypeName(),isSTLbase)));
3350  break;
3351  case kVectorPtrLooper:
3352  case kGenericLooper:
3353  default:
3354  // For now TBufferXML would force use to allocate the data buffer each time and copy into the real thing.
3355  readSequence->AddAction(GetNumericCollectionReadAction<GenericLooper>(oldClass->GetCollectionProxy()->GetType(), new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetTypeName(),isSTLbase)));
3356  break;
3357  }
3358  }
3359  }
3360  }
3361  }
3362  } else {
3363  if (fOldVersion<3){ // case of old TStreamerInfo
3364  if (newClass && newClass != oldClass) {
3365  if (element->GetStreamer()) {
3366  readSequence->AddAction(ReadSTL<ReadArraySTLMemberWiseChangedClass,ReadSTLObjectWiseStreamerV2>, new TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,newClass,element->GetStreamer(),element->GetTypeName(),isSTLbase));
3367  } else {
3368  readSequence->AddAction(ReadSTL<ReadArraySTLMemberWiseChangedClass,ReadSTLObjectWiseFastArrayV2>, new TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,newClass,element->GetTypeName(),isSTLbase));
3369  }
3370  } else {
3371  if (element->GetStreamer()) {
3372  readSequence->AddAction(ReadSTL<ReadArraySTLMemberWiseSameClass,ReadSTLObjectWiseStreamerV2>, new TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,element->GetStreamer(),element->GetTypeName(),isSTLbase));
3373  } else {
3374  readSequence->AddAction(ReadSTL<ReadArraySTLMemberWiseSameClass,ReadSTLObjectWiseFastArrayV2>, new TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,element->GetTypeName(),isSTLbase));
3375  }
3376  }
3377  } else {
3378  if (newClass && newClass != oldClass) {
3379  if (element->GetStreamer()) {
3380  readSequence->AddAction(ReadSTL<ReadArraySTLMemberWiseChangedClass,ReadSTLObjectWiseStreamer>, new TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,newClass,element->GetStreamer(),element->GetTypeName(),isSTLbase));
3381  } else {
3382  readSequence->AddAction(ReadSTL<ReadArraySTLMemberWiseChangedClass,ReadSTLObjectWiseFastArray>, new TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,newClass,element->GetTypeName(),isSTLbase));
3383  }
3384  } else {
3385  if (element->GetStreamer()) {
3386  readSequence->AddAction(ReadSTL<ReadArraySTLMemberWiseSameClass,ReadSTLObjectWiseStreamer>, new TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,element->GetStreamer(),element->GetTypeName(),isSTLbase));
3387  } else {
3388  readSequence->AddAction(ReadSTL<ReadArraySTLMemberWiseSameClass,ReadSTLObjectWiseFastArray>, new TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,element->GetTypeName(),isSTLbase));
3389  }
3390  }
3391  }
3392  }
3393  break;
3394  }
3395 
3396  case TStreamerInfo::kConv + TStreamerInfo::kBool:
3397  AddReadConvertAction<Bool_t>(readSequence, compinfo->fNewType, new TConfiguration(this,i,compinfo,compinfo->fOffset) );
3398  break;
3399  case TStreamerInfo::kConv + TStreamerInfo::kChar:
3400  AddReadConvertAction<Char_t>(readSequence, compinfo->fNewType, new TConfiguration(this,i,compinfo,compinfo->fOffset) );
3401  break;
3402  case TStreamerInfo::kConv + TStreamerInfo::kShort:
3403  AddReadConvertAction<Short_t>(readSequence, compinfo->fNewType, new TConfiguration(this,i,compinfo,compinfo->fOffset) );
3404  break;
3405  case TStreamerInfo::kConv + TStreamerInfo::kInt:
3406  AddReadConvertAction<Int_t>(readSequence, compinfo->fNewType, new TConfiguration(this,i,compinfo,compinfo->fOffset) );
3407  break;
3408  case TStreamerInfo::kConv + TStreamerInfo::kLong:
3409  AddReadConvertAction<Long_t>(readSequence, compinfo->fNewType, new TConfiguration(this,i,compinfo,compinfo->fOffset) );
3410  break;
3411  case TStreamerInfo::kConv + TStreamerInfo::kLong64:
3412  AddReadConvertAction<Long64_t>(readSequence, compinfo->fNewType, new TConfiguration(this,i,compinfo,compinfo->fOffset) );
3413  break;
3414  case TStreamerInfo::kConv + TStreamerInfo::kFloat:
3415  AddReadConvertAction<Float_t>(readSequence, compinfo->fNewType, new TConfiguration(this,i,compinfo,compinfo->fOffset) );
3416  break;
3417  case TStreamerInfo::kConv + TStreamerInfo::kDouble:
3418  AddReadConvertAction<Double_t>(readSequence, compinfo->fNewType, new TConfiguration(this,i,compinfo,compinfo->fOffset) );
3419  break;
3420  case TStreamerInfo::kConv + TStreamerInfo::kUChar:
3421  AddReadConvertAction<UChar_t>(readSequence, compinfo->fNewType, new TConfiguration(this,i,compinfo,compinfo->fOffset) );
3422  break;
3423  case TStreamerInfo::kConv + TStreamerInfo::kUShort:
3424  AddReadConvertAction<UShort_t>(readSequence, compinfo->fNewType, new TConfiguration(this,i,compinfo,compinfo->fOffset) );
3425  break;
3426  case TStreamerInfo::kConv + TStreamerInfo::kUInt:
3427  AddReadConvertAction<UInt_t>(readSequence, compinfo->fNewType, new TConfiguration(this,i,compinfo,compinfo->fOffset) );
3428  break;
3429  case TStreamerInfo::kConv + TStreamerInfo::kULong:
3430  AddReadConvertAction<ULong_t>(readSequence, compinfo->fNewType, new TConfiguration(this,i,compinfo,compinfo->fOffset) );
3431  break;
3432  case TStreamerInfo::kConv + TStreamerInfo::kULong64:
3433  AddReadConvertAction<ULong64_t>(readSequence, compinfo->fNewType, new TConfiguration(this,i,compinfo,compinfo->fOffset) );
3434  break;
3435  case TStreamerInfo::kConv + TStreamerInfo::kBits:
3436  AddReadConvertAction<BitsMarker>(readSequence, compinfo->fNewType, new TBitsConfiguration(this,i,compinfo,compinfo->fOffset) );
3437  break;
3438  case TStreamerInfo::kConv + TStreamerInfo::kFloat16: {
3439  if (element->GetFactor() != 0) {
3440  AddReadConvertAction<WithFactorMarker<float> >(readSequence, compinfo->fNewType, new TConfWithFactor(this,i,compinfo,compinfo->fOffset,element->GetFactor(),element->GetXmin()) );
3441  } else {
3442  Int_t nbits = (Int_t)element->GetXmin();
3443  if (!nbits) nbits = 12;
3444  AddReadConvertAction<NoFactorMarker<float> >(readSequence, compinfo->fNewType, new TConfNoFactor(this,i,compinfo,compinfo->fOffset,nbits) );
3445  }
3446  break;
3447  }
3448  case TStreamerInfo::kConv + TStreamerInfo::kDouble32: {
3449  if (element->GetFactor() != 0) {
3450  AddReadConvertAction<WithFactorMarker<double> >(readSequence, compinfo->fNewType, new TConfWithFactor(this,i,compinfo,compinfo->fOffset,element->GetFactor(),element->GetXmin()) );
3451  } else {
3452  Int_t nbits = (Int_t)element->GetXmin();
3453  if (!nbits) {
3454  AddReadConvertAction<Float_t>(readSequence, compinfo->fNewType, new TConfiguration(this,i,compinfo,compinfo->fOffset) );
3455  } else {
3456  AddReadConvertAction<NoFactorMarker<double> >(readSequence, compinfo->fNewType, new TConfNoFactor(this,i,compinfo,compinfo->fOffset,nbits) );
3457  }
3458  }
3459  break;
3460  }
3461  default:
3462  readSequence->AddAction( GenericReadAction, new TGenericConfiguration(this,i,compinfo) );
3463  break;
3464  }
3465  if (element->TestBit(TStreamerElement::kCache)) {
3466  TConfiguredAction action( readSequence->fActions.back() ); // Action is moved, we must pop it next.
3467  readSequence->fActions.pop_back();
3468  readSequence->AddAction( UseCache, new TConfigurationUseCache(this,action,element->TestBit(TStreamerElement::kRepeat)) );
3469  }
3470 }
3471 
3472 ////////////////////////////////////////////////////////////////////////////////
3473 /// Add a read text action for the given element.
3474 
3475 void TStreamerInfo::AddReadTextAction(TStreamerInfoActions::TActionSequence *readSequence, Int_t i, TStreamerInfo::TCompInfo *compinfo)
3476 {
3477  TStreamerElement *element = compinfo->fElem;
3478 
3479  if (element->TestBit(TStreamerElement::kWrite))
3480  return;
3481 
3482  Bool_t generic = kFALSE, isBase = kFALSE;
3483 
3484  switch (compinfo->fType) {
3485  case TStreamerInfo::kTObject:
3486  if (element->IsBase())
3487  isBase = kTRUE;
3488  // readSequence->AddAction( ReadTextTObjectBase, new TConfiguration(this,i,compinfo,compinfo->fOffset) );
3489  else
3490  readSequence->AddAction(ReadTextTObject, new TConfiguration(this, i, compinfo, compinfo->fOffset));
3491  break;
3492 
3493  case TStreamerInfo::kTNamed:
3494  if (element->IsBase())
3495  isBase = kTRUE;
3496  // generic = kTRUE; // for the base class one cannot call TClass::Streamer() as performed for the normal object
3497  else
3498  readSequence->AddAction(ReadTextTNamed, new TConfiguration(this, i, compinfo, compinfo->fOffset));
3499  break;
3500 
3501  case TStreamerInfo::kObject: // Class derived from TObject
3502  case TStreamerInfo::kAny: // Class NOT derived from TObject
3503  case TStreamerInfo::kOffsetL + TStreamerInfo::kObject:
3504  case TStreamerInfo::kAny + TStreamerInfo::kOffsetL:
3505  readSequence->AddAction(ReadTextObject, new TConfiguration(this, i, compinfo, compinfo->fOffset));
3506  break;
3507 
3508  case TStreamerInfo::kSTLp: // Pointer to container with no virtual table (stl) and no comment
3509  case TStreamerInfo::kSTLp +
3510  TStreamerInfo::kOffsetL: // array of pointers to container with no virtual table (stl) and no comment
3511  readSequence->AddAction(ReadSTLp<true>, new TConfiguration(this, i, compinfo, compinfo->fOffset));
3512  break;
3513 
3514  case TStreamerInfo::kStreamLoop:
3515  case TStreamerInfo::kOffsetL + TStreamerInfo::kStreamLoop:
3516  readSequence->AddAction(ReadStreamerLoop<true>, new TConfiguration(this, i, compinfo, compinfo->fOffset));
3517  break;
3518 
3519  case TStreamerInfo::kBase: isBase = kTRUE; break;
3520 
3521  case TStreamerInfo::kStreamer:
3522  readSequence->AddAction(ReadTextStreamer, new TGenericConfiguration(this, i, compinfo));
3523  break;
3524 
3525  default: generic = kTRUE; break;
3526  }
3527 
3528  if (isBase) {
3529  if (compinfo->fStreamer) {
3530  readSequence->AddAction(ReadTextStreamer, new TGenericConfiguration(this, i, compinfo));
3531  } else {
3532  readSequence->AddAction(ReadTextBaseClass, new TGenericConfiguration(this, i, compinfo));
3533  }
3534  } else if (generic)
3535  readSequence->AddAction(GenericReadAction, new TGenericConfiguration(this, i, compinfo));
3536 }
3537 
3538 ////////////////////////////////////////////////////////////////////////////////
3539 /// Add a read action for the given element.
3540 /// This is for streaming via a TClonesArray (or a vector of pointers of this type).
3541 
3542 void TStreamerInfo::AddReadMemberWiseVecPtrAction(TStreamerInfoActions::TActionSequence *readSequence, Int_t i, TStreamerInfo::TCompInfo *compinfo)
3543 {
3544  TStreamerElement *element = compinfo->fElem;
3545 
3546  if (element->TestBit(TStreamerElement::kWrite)) return;
3547 
3548  if (element->TestBit(TStreamerElement::kCache)) {
3549  TConfiguredAction action( GetCollectionReadAction<VectorLooper>(this,element,compinfo->fType,i,compinfo,compinfo->fOffset) );
3550  readSequence->AddAction( UseCacheVectorPtrLoop, new TConfigurationUseCache(this,action,element->TestBit(TStreamerElement::kRepeat)) );
3551  } else {
3552  readSequence->AddAction( GetCollectionReadAction<VectorPtrLooper>(this,element,compinfo->fType,i,compinfo,compinfo->fOffset) );
3553  }
3554 }
3555 
3556 ////////////////////////////////////////////////////////////////////////////////
3557 
3558 void TStreamerInfo::AddWriteAction(TStreamerInfoActions::TActionSequence *writeSequence, Int_t i, TStreamerInfo::TCompInfo *compinfo)
3559 {
3560  TStreamerElement *element = compinfo->fElem;
3561  if (element->TestBit(TStreamerElement::kCache) && !element->TestBit(TStreamerElement::kWrite)) {
3562  // Skip element cached for reading purposes.
3563  return;
3564  }
3565  if (element->GetType() >= kArtificial && !element->TestBit(TStreamerElement::kWrite)) {
3566  // Skip artificial element used for reading purposes.
3567  return;
3568  }
3569  switch (compinfo->fType) {
3570  // write basic types
3571  case TStreamerInfo::kBool: writeSequence->AddAction( WriteBasicType<Bool_t>, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3572  case TStreamerInfo::kChar: writeSequence->AddAction( WriteBasicType<Char_t>, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3573  case TStreamerInfo::kShort: writeSequence->AddAction( WriteBasicType<Short_t>, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3574  case TStreamerInfo::kInt: writeSequence->AddAction( WriteBasicType<Int_t>, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3575  case TStreamerInfo::kLong: writeSequence->AddAction( WriteBasicType<Long_t>, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3576  case TStreamerInfo::kLong64: writeSequence->AddAction( WriteBasicType<Long64_t>, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3577  case TStreamerInfo::kFloat: writeSequence->AddAction( WriteBasicType<Float_t>, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3578  case TStreamerInfo::kDouble: writeSequence->AddAction( WriteBasicType<Double_t>, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3579  case TStreamerInfo::kUChar: writeSequence->AddAction( WriteBasicType<UChar_t>, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3580  case TStreamerInfo::kUShort: writeSequence->AddAction( WriteBasicType<UShort_t>, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3581  case TStreamerInfo::kUInt: writeSequence->AddAction( WriteBasicType<UInt_t>, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3582  case TStreamerInfo::kULong: writeSequence->AddAction( WriteBasicType<ULong_t>, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3583  case TStreamerInfo::kULong64: writeSequence->AddAction( WriteBasicType<ULong64_t>, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3584  // case TStreamerInfo::kBits: writeSequence->AddAction( WriteBasicType<BitsMarker>, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3585  /*case TStreamerInfo::kFloat16: {
3586  if (element->GetFactor() != 0) {
3587  writeSequence->AddAction( WriteBasicType_WithFactor<float>, new TConfWithFactor(this,i,compinfo,compinfo->fOffset,element->GetFactor(),element->GetXmin()) );
3588  } else {
3589  Int_t nbits = (Int_t)element->GetXmin();
3590  if (!nbits) nbits = 12;
3591  writeSequence->AddAction( WriteBasicType_NoFactor<float>, new TConfNoFactor(this,i,compinfo,compinfo->fOffset,nbits) );
3592  }
3593  break;
3594  } */
3595  /*case TStreamerInfo::kDouble32: {
3596  if (element->GetFactor() != 0) {
3597  writeSequence->AddAction( WriteBasicType_WithFactor<double>, new TConfWithFactor(this,i,compinfo,compinfo->fOffset,element->GetFactor(),element->GetXmin()) );
3598  } else {
3599  Int_t nbits = (Int_t)element->GetXmin();
3600  if (!nbits) {
3601  writeSequence->AddAction( ConvertBasicType<float,double>, new TConfiguration(this,i,compinfo,compinfo->fOffset) );
3602  } else {
3603  writeSequence->AddAction( WriteBasicType_NoFactor<double>, new TConfNoFactor(this,i,compinfo,compinfo->fOffset,nbits) );
3604  }
3605  }
3606  break;
3607  } */
3608  //case TStreamerInfo::kTNamed: writeSequence->AddAction( WriteTNamed, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3609  // Idea: We should calculate the CanIgnoreTObjectStreamer here and avoid calling the
3610  // Streamer alltogether.
3611  //case TStreamerInfo::kTObject: writeSequence->AddAction( WriteTObject, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3612  //case TStreamerInfo::kTString: writeSequence->AddAction( WriteTString, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3613  /*case TStreamerInfo::kSTL: {
3614  TClass *newClass = element->GetNewClass();
3615  TClass *oldClass = element->GetClassPointer();
3616  Bool_t isSTLbase = element->IsBase() && element->IsA()!=TStreamerBase::Class();
3617 
3618  if (element->GetArrayLength() <= 1) {
3619  if (newClass && newClass != oldClass) {
3620  if (element->GetStreamer()) {
3621  writeSequence->AddAction(WriteSTL<WriteSTLMemberWiseChangedClass,WriteSTLObjectWiseStreamer>, new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetStreamer(),element->GetTypeName(),isSTLbase));
3622  } else {
3623  writeSequence->AddAction(WriteSTL<WriteSTLMemberWiseChangedClass,WriteSTLObjectWiseFastArray>, new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetTypeName(),isSTLbase));
3624  }
3625  } else {
3626  if (element->GetStreamer()) {
3627  writeSequence->AddAction(WriteSTL<WriteSTLMemberWiseSameClass,WriteSTLObjectWiseStreamer>, new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetStreamer(),element->GetTypeName(),isSTLbase));
3628  } else {
3629  writeSequence->AddAction(WriteSTL<WriteSTLMemberWiseSameClass,WriteSTLObjectWiseFastArray>, new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetTypeName(),isSTLbase));
3630  }
3631  }
3632  } else {
3633  if (newClass && newClass != oldClass) {
3634  if (element->GetStreamer()) {
3635  writeSequence->AddAction(WriteSTL<WriteArraySTLMemberWiseChangedClass,WriteSTLObjectWiseStreamer>, new TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,newClass,element->GetStreamer(),element->GetTypeName(),isSTLbase));
3636  } else {
3637  writeSequence->AddAction(WriteSTL<WriteArraySTLMemberWiseChangedClass,WriteSTLObjectWiseFastArray>, new TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,newClass,element->GetTypeName(),isSTLbase));
3638  }
3639  } else {
3640  if (element->GetStreamer()) {
3641  writeSequence->AddAction(WriteSTL<WriteArraySTLMemberWiseSameClass,WriteSTLObjectWiseStreamer>, new TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,element->GetStreamer(),element->GetTypeName(),isSTLbase));
3642  } else {
3643  writeSequence->AddAction(WriteSTL<WriteArraySTLMemberWiseSameClass,WriteSTLObjectWiseFastArray>, new TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,element->GetTypeName(),isSTLbase));
3644  }
3645  }
3646  }
3647  break;
3648  } */
3649  default:
3650  writeSequence->AddAction( GenericWriteAction, new TGenericConfiguration(this,i,compinfo) );
3651  break;
3652  }
3653 #if defined(CDJ_NO_COMPILE)
3654  if (element->TestBit(TStreamerElement::kCache)) {
3655  TConfiguredAction action( writeSequence->fActions.back() ); // Action is moved, we must pop it next.
3656  writeSequence->fActions.pop_back();
3657  writeSequence->AddAction( UseCache, new TConfigurationUseCache(this,action,element->TestBit(TStreamerElement::kRepeat)) );
3658  }
3659 #endif
3660 }
3661 
3662 ////////////////////////////////////////////////////////////////////////////////
3663 
3664 void TStreamerInfo::AddWriteTextAction(TStreamerInfoActions::TActionSequence *writeSequence, Int_t i, TStreamerInfo::TCompInfo *compinfo)
3665 {
3666  TStreamerElement *element = compinfo->fElem;
3667  if (element->TestBit(TStreamerElement::kCache) && !element->TestBit(TStreamerElement::kWrite)) {
3668  // Skip element cached for reading purposes.
3669  return;
3670  }
3671  if (element->GetType() >= kArtificial && !element->TestBit(TStreamerElement::kWrite)) {
3672  // Skip artificial element used for reading purposes.
3673  return;
3674  }
3675 
3676  Bool_t generic = kFALSE, isBase = kFALSE;
3677 
3678  switch (compinfo->fType) {
3679  // write basic types
3680  case TStreamerInfo::kBool:
3681  writeSequence->AddAction(WriteBasicType<Bool_t>, new TConfiguration(this, i, compinfo, compinfo->fOffset));
3682  break;
3683  case TStreamerInfo::kChar:
3684  writeSequence->AddAction(WriteBasicType<Char_t>, new TConfiguration(this, i, compinfo, compinfo->fOffset));
3685  break;
3686  case TStreamerInfo::kShort:
3687  writeSequence->AddAction(WriteBasicType<Short_t>, new TConfiguration(this, i, compinfo, compinfo->fOffset));
3688  break;
3689  case TStreamerInfo::kInt:
3690  writeSequence->AddAction(WriteBasicType<Int_t>, new TConfiguration(this, i, compinfo, compinfo->fOffset));
3691  break;
3692  case TStreamerInfo::kLong:
3693  writeSequence->AddAction(WriteBasicType<Long_t>, new TConfiguration(this, i, compinfo, compinfo->fOffset));
3694  break;
3695  case TStreamerInfo::kLong64:
3696  writeSequence->AddAction(WriteBasicType<Long64_t>, new TConfiguration(this, i, compinfo, compinfo->fOffset));
3697  break;
3698  case TStreamerInfo::kFloat:
3699  writeSequence->AddAction(WriteBasicType<Float_t>, new TConfiguration(this, i, compinfo, compinfo->fOffset));
3700  break;
3701  case TStreamerInfo::kDouble:
3702  writeSequence->AddAction(WriteBasicType<Double_t>, new TConfiguration(this, i, compinfo, compinfo->fOffset));
3703  break;
3704  case TStreamerInfo::kUChar:
3705  writeSequence->AddAction(WriteBasicType<UChar_t>, new TConfiguration(this, i, compinfo, compinfo->fOffset));
3706  break;
3707  case TStreamerInfo::kUShort:
3708  writeSequence->AddAction(WriteBasicType<UShort_t>, new TConfiguration(this, i, compinfo, compinfo->fOffset));
3709  break;
3710  case TStreamerInfo::kUInt:
3711  writeSequence->AddAction(WriteBasicType<UInt_t>, new TConfiguration(this, i, compinfo, compinfo->fOffset));
3712  break;
3713  case TStreamerInfo::kULong:
3714  writeSequence->AddAction(WriteBasicType<ULong_t>, new TConfiguration(this, i, compinfo, compinfo->fOffset));
3715  break;
3716  case TStreamerInfo::kULong64:
3717  writeSequence->AddAction(WriteBasicType<ULong64_t>, new TConfiguration(this, i, compinfo, compinfo->fOffset));
3718  break;
3719 
3720  case TStreamerInfo::kTObject:
3721  if (element->IsBase())
3722  isBase = kTRUE;
3723  else
3724  writeSequence->AddAction(WriteTextTObject, new TConfiguration(this, i, compinfo, compinfo->fOffset));
3725  break;
3726 
3727  case TStreamerInfo::kTNamed:
3728  if (element->IsBase())
3729  isBase = kTRUE;
3730  else
3731  writeSequence->AddAction(WriteTextTNamed, new TConfiguration(this, i, compinfo, compinfo->fOffset));
3732  break;
3733 
3734  case TStreamerInfo::kSTLp: // Pointer to container with no virtual table (stl) and no comment
3735  case TStreamerInfo::kSTLp +
3736  TStreamerInfo::kOffsetL: // array of pointers to container with no virtual table (stl) and no comment
3737  writeSequence->AddAction(WriteSTLp<true>, new TConfiguration(this, i, compinfo, compinfo->fOffset));
3738  break;
3739 
3740  case TStreamerInfo::kStreamLoop:
3741  case TStreamerInfo::kOffsetL + TStreamerInfo::kStreamLoop:
3742  writeSequence->AddAction(WriteStreamerLoop<true>, new TConfiguration(this, i, compinfo, compinfo->fOffset));
3743  break;
3744 
3745  case TStreamerInfo::kBase: isBase = kTRUE; break;
3746 
3747  case TStreamerInfo::kStreamer:
3748  writeSequence->AddAction(WriteTextStreamer, new TGenericConfiguration(this, i, compinfo));
3749  break;
3750 
3751  // case TStreamerInfo::kBits: writeSequence->AddAction( WriteBasicType<BitsMarker>, new
3752  // TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3753  /*case TStreamerInfo::kFloat16: {
3754  if (element->GetFactor() != 0) {
3755  writeSequence->AddAction( WriteBasicType_WithFactor<float>, new
3756  TConfWithFactor(this,i,compinfo,compinfo->fOffset,element->GetFactor(),element->GetXmin()) );
3757  } else {
3758  Int_t nbits = (Int_t)element->GetXmin();
3759  if (!nbits) nbits = 12;
3760  writeSequence->AddAction( WriteBasicType_NoFactor<float>, new
3761  TConfNoFactor(this,i,compinfo,compinfo->fOffset,nbits) );
3762  }
3763  break;
3764  } */
3765  /*case TStreamerInfo::kDouble32: {
3766  if (element->GetFactor() != 0) {
3767  writeSequence->AddAction( WriteBasicType_WithFactor<double>, new
3768  TConfWithFactor(this,i,compinfo,compinfo->fOffset,element->GetFactor(),element->GetXmin()) );
3769  } else {
3770  Int_t nbits = (Int_t)element->GetXmin();
3771  if (!nbits) {
3772  writeSequence->AddAction( ConvertBasicType<float,double>, new
3773  TConfiguration(this,i,compinfo,compinfo->fOffset) );
3774  } else {
3775  writeSequence->AddAction( WriteBasicType_NoFactor<double>, new
3776  TConfNoFactor(this,i,compinfo,compinfo->fOffset,nbits) );
3777  }
3778  }
3779  break;
3780  } */
3781  // case TStreamerInfo::kTNamed: writeSequence->AddAction( WriteTNamed, new
3782  // TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3783  // Idea: We should calculate the CanIgnoreTObjectStreamer here and avoid calling the
3784  // Streamer alltogether.
3785  // case TStreamerInfo::kTObject: writeSequence->AddAction( WriteTObject, new
3786  // TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3787  // case TStreamerInfo::kTString: writeSequence->AddAction( WriteTString, new
3788  // TConfiguration(this,i,compinfo,compinfo->fOffset) ); break;
3789  /*case TStreamerInfo::kSTL: {
3790  TClass *newClass = element->GetNewClass();
3791  TClass *oldClass = element->GetClassPointer();
3792  Bool_t isSTLbase = element->IsBase() && element->IsA()!=TStreamerBase::Class();
3793 
3794  if (element->GetArrayLength() <= 1) {
3795  if (newClass && newClass != oldClass) {
3796  if (element->GetStreamer()) {
3797  writeSequence->AddAction(WriteSTL<WriteSTLMemberWiseChangedClass,WriteSTLObjectWiseStreamer>, new
3798  TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetStreamer(),element->GetTypeName(),isSTLbase));
3799  } else {
3800  writeSequence->AddAction(WriteSTL<WriteSTLMemberWiseChangedClass,WriteSTLObjectWiseFastArray>, new
3801  TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetTypeName(),isSTLbase));
3802  }
3803  } else {
3804  if (element->GetStreamer()) {
3805  writeSequence->AddAction(WriteSTL<WriteSTLMemberWiseSameClass,WriteSTLObjectWiseStreamer>, new
3806  TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetStreamer(),element->GetTypeName(),isSTLbase));
3807  } else {
3808  writeSequence->AddAction(WriteSTL<WriteSTLMemberWiseSameClass,WriteSTLObjectWiseFastArray>, new
3809  TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetTypeName(),isSTLbase));
3810  }
3811  }
3812  } else {
3813  if (newClass && newClass != oldClass) {
3814  if (element->GetStreamer()) {
3815  writeSequence->AddAction(WriteSTL<WriteArraySTLMemberWiseChangedClass,WriteSTLObjectWiseStreamer>, new
3816  TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,newClass,element->GetStreamer(),element->GetTypeName(),isSTLbase));
3817  } else {
3818  writeSequence->AddAction(WriteSTL<WriteArraySTLMemberWiseChangedClass,WriteSTLObjectWiseFastArray>, new
3819  TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,newClass,element->GetTypeName(),isSTLbase));
3820  }
3821  } else {
3822  if (element->GetStreamer()) {
3823  writeSequence->AddAction(WriteSTL<WriteArraySTLMemberWiseSameClass,WriteSTLObjectWiseStreamer>, new
3824  TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,element->GetStreamer(),element->GetTypeName(),isSTLbase));
3825  } else {
3826  writeSequence->AddAction(WriteSTL<WriteArraySTLMemberWiseSameClass,WriteSTLObjectWiseFastArray>, new
3827  TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,element->GetTypeName(),isSTLbase));
3828  }
3829  }
3830  }
3831  break;
3832  } */
3833  default: generic = kTRUE; break;
3834  }
3835 
3836  if (isBase) {
3837  if (compinfo->fStreamer) {
3838  writeSequence->AddAction(WriteTextStreamer, new TGenericConfiguration(this, i, compinfo));
3839  } else {
3840  writeSequence->AddAction(WriteTextBaseClass, new TGenericConfiguration(this, i, compinfo));
3841  }
3842 
3843  } else
3844 
3845  // use generic write action when special handling is not provided
3846  if (generic)
3847  writeSequence->AddAction(GenericWriteAction, new TGenericConfiguration(this, i, compinfo));
3848 
3849 #if defined(CDJ_NO_COMPILE)
3850  if (element->TestBit(TStreamerElement::kCache)) {
3851  TConfiguredAction action(writeSequence->fActions.back()); // Action is moved, we must pop it next.
3852  writeSequence->fActions.pop_back();
3853  writeSequence->AddAction(UseCache,
3854  new TConfigurationUseCache(this, action, element->TestBit(TStreamerElement::kRepeat)));
3855  }
3856 #endif
3857 }
3858 
3859 ////////////////////////////////////////////////////////////////////////////////
3860 /// This is for streaming via a TClonesArray (or a vector of pointers of this type).
3861 
3862 void TStreamerInfo::AddWriteMemberWiseVecPtrAction(TStreamerInfoActions::TActionSequence *writeSequence, Int_t i, TStreamerInfo::TCompInfo *compinfo)
3863 {
3864  TStreamerElement *element = compinfo->fElem;
3865  if (element->TestBit(TStreamerElement::kCache) && !element->TestBit(TStreamerElement::kWrite)) {
3866  // Skip element cached for reading purposes.
3867  return;
3868  }
3869  if (element->GetType() >= kArtificial && !element->TestBit(TStreamerElement::kWrite)) {
3870  // Skip artificial element used for reading purposes.
3871  return;
3872  }
3873 
3874 #if defined(CDJ_NO_COMPILE)
3875  if (element->TestBit(TStreamerElement::kCache)) {
3876  TConfiguredAction action( GetCollectionWriteAction<VectorLooper>(this,element,compinfo->fType,i,compinfo,compinfo->fOffset) );
3877  writeSequence->AddAction( UseCacheVectorPtrLoop, new TConfigurationUseCache(this,action,element->TestBit(TStreamerElement::kRepeat)) );
3878  } else {
3879  writeSequence->Addaction( GetCollectionWriteAction<VectorPtrLooper>(this,element,compinfo->fType,i,compinfo,compinfo->fOffset) );
3880  }
3881 #else
3882  writeSequence->AddAction( VectorPtrLooper::GenericWrite, new TGenericConfiguration(this,i,compinfo) );
3883 #endif
3884 
3885 }
3886 
3887 ////////////////////////////////////////////////////////////////////////////////
3888 /// Create the bundle of the actions necessary for the streaming memberwise of the content described by 'info' into the collection described by 'proxy'
3889 
3890 TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::CreateReadMemberWiseActions(TVirtualStreamerInfo *info, TVirtualCollectionProxy &proxy)
3891 {
3892  if (info == 0) {
3893  return new TStreamerInfoActions::TActionSequence(0,0);
3894  }
3895 
3896  TStreamerInfo *sinfo = static_cast<TStreamerInfo*>(info);
3897 
3898  UInt_t ndata = info->GetElements()->GetEntries();
3899  TStreamerInfoActions::TActionSequence *sequence = new TStreamerInfoActions::TActionSequence(info,ndata);
3900  if (IsDefaultVector(proxy))
3901  {
3902  if (proxy.HasPointers()) {
3903  // Instead of the creating a new one let's copy the one from the StreamerInfo.
3904  delete sequence;
3905 
3906  sequence = sinfo->GetReadMemberWiseActions(kTRUE)->CreateCopy();
3907 
3908  return sequence;
3909  }
3910 
3911  // We can speed up the iteration in case of vector. We also know that all emulated collection are stored internally as a vector.
3912  Long_t increment = proxy.GetIncrement();
3913  sequence->fLoopConfig = new TVectorLoopConfig(&proxy, increment, /* read */ kTRUE);
3914  } else if (proxy.GetCollectionType() == ROOT::kSTLset || proxy.GetCollectionType() == ROOT::kSTLunorderedset
3915  || proxy.GetCollectionType() == ROOT::kSTLmultiset || proxy.GetCollectionType() == ROOT::kSTLunorderedmultiset
3916  || proxy.GetCollectionType() == ROOT::kSTLmap || proxy.GetCollectionType() == ROOT::kSTLmultimap
3917  || proxy.GetCollectionType() == ROOT::kSTLunorderedmap || proxy.GetCollectionType() == ROOT::kSTLunorderedmultimap)
3918  {
3919  Long_t increment = proxy.GetIncrement();
3920  sequence->fLoopConfig = new TVectorLoopConfig(&proxy, increment, /* read */ kTRUE);
3921  // sequence->fLoopConfig = new TAssocLoopConfig(proxy);
3922  } else {
3923  sequence->fLoopConfig = new TGenericLoopConfig(&proxy, /* read */ kTRUE);
3924  }
3925  for (UInt_t i = 0; i < ndata; ++i) {
3926  TStreamerElement *element = (TStreamerElement*) info->GetElements()->At(i);
3927  if (!element) {
3928  break;
3929  }
3930  if (element->GetType() < 0) {
3931  // -- Skip an ignored TObject base class.
3932  // Note: The only allowed negative value here is -1, and signifies that Build() has found a TObject
3933  // base class and TClass::IgnoreTObjectStreamer() was called. In this case the compiled version of the
3934  // elements omits the TObject base class element, which has to be compensated for by TTree::Bronch()
3935  // when it is making branches for a split object.
3936  continue;
3937  }
3938  if (element->TestBit(TStreamerElement::kWrite)) {
3939  // Skip element that only for writing.
3940  continue;
3941  }
3942  TStreamerBase *baseEl = dynamic_cast<TStreamerBase*>(element);
3943  if (baseEl) {
3944  if (!baseEl->TestBit(TStreamerElement::kWarned) && baseEl->GetErrorMessage()[0]) {
3945  // There was a problem with the checksum, the user likely did not
3946  // increment the version number of the derived class when the
3947  // base class changed. Since we will be member wise streaming
3948  // this class, let's warn the user that something is wrong.
3949  ::Warning("CreateReadMemberWiseActions","%s",
3950  baseEl->GetErrorMessage());
3951  baseEl->SetBit(TStreamerElement::kWarned);
3952  }
3953  }
3954 
3955  TStreamerInfo::TCompInfo_t *compinfo = sinfo->fCompFull[i];
3956 
3957  Int_t asize = element->GetSize();
3958  if (element->GetArrayLength()) {
3959  asize /= element->GetArrayLength();
3960  }
3961  Int_t oldType = element->GetType();
3962  Int_t newType = element->GetNewType();
3963 
3964  Int_t offset = element->GetOffset();
3965  if (newType != oldType) {
3966  if (newType > 0) {
3967  if (oldType != TVirtualStreamerInfo::kCounter) {
3968  oldType += TVirtualStreamerInfo::kConv;
3969  }
3970  } else {
3971  oldType += TVirtualStreamerInfo::kSkip;
3972  }
3973  }
3974  switch (SelectLooper(proxy)) {
3975  case kAssociativeLooper:
3976 // } else if (proxy.GetCollectionType() == ROOT::kSTLset || proxy.GetCollectionType() == ROOT::kSTLmultiset
3977 // || proxy.GetCollectionType() == ROOT::kSTLmap || proxy.GetCollectionType() == ROOT::kSTLmultimap) {
3978 // sequence->AddAction( GenericAssocCollectionAction, new TConfigSTL(info,i,compinfo,offset,0,proxy.GetCollectionClass(),0,0) );
3979  case kVectorLooper:
3980  case kVectorPtrLooper:
3981  // We can speed up the iteration in case of vector. We also know that all emulated collection are stored internally as a vector.
3982  if (element->TestBit(TStreamerElement::kCache)) {
3983  TConfiguredAction action( GetCollectionReadAction<VectorLooper>(info,element,oldType,i,compinfo,offset) );
3984  sequence->AddAction( UseCacheVectorLoop, new TConfigurationUseCache(info,action,element->TestBit(TStreamerElement::kRepeat)) );
3985  } else {
3986  sequence->AddAction( GetCollectionReadAction<VectorLooper>(info,element,oldType,i,compinfo,offset));
3987  }
3988  break;
3989  case kGenericLooper:
3990  default:
3991  // The usual collection case.
3992  if (element->TestBit(TStreamerElement::kCache)) {
3993  TConfiguredAction action( GetCollectionReadAction<VectorLooper>(info,element,oldType,i,compinfo,offset) );
3994  sequence->AddAction( UseCacheGenericCollection, new TConfigurationUseCache(info,action,element->TestBit(TStreamerElement::kRepeat)) );
3995  } else {
3996  sequence->AddAction( GetCollectionReadAction<GenericLooper>(info,element,oldType,i,compinfo,offset) );
3997  }
3998  break;
3999  }
4000  }
4001  return sequence;
4002 }
4003 
4004 ////////////////////////////////////////////////////////////////////////////////
4005 /// Create the bundle of the actions necessary for the streaming memberwise of the content described by 'info' into the collection described by 'proxy'
4006 
4007 TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::CreateWriteMemberWiseActions(TVirtualStreamerInfo *info, TVirtualCollectionProxy &proxy)
4008 {
4009  if (info == 0) {
4010  return new TStreamerInfoActions::TActionSequence(0,0);
4011  }
4012 
4013  UInt_t ndata = info->GetElements()->GetEntries();
4014  TStreamerInfo *sinfo = static_cast<TStreamerInfo*>(info);
4015  TStreamerInfoActions::TActionSequence *sequence = new TStreamerInfoActions::TActionSequence(info,ndata);
4016 
4017  if (IsDefaultVector(proxy))
4018  {
4019  if (proxy.HasPointers()) {
4020  // Instead of the creating a new one let's copy the one from the StreamerInfo.
4021  delete sequence;
4022 
4023  sequence = sinfo->GetWriteMemberWiseActions(kTRUE)->CreateCopy();
4024 
4025  return sequence;
4026  }
4027 
4028  // We can speed up the iteration in case of vector. We also know that all emulated collection are stored internally as a vector.
4029  Long_t increment = proxy.GetIncrement();
4030  sequence->fLoopConfig = new TVectorLoopConfig(&proxy, increment, /* read */ kFALSE);
4031  /*} else if (proxy.GetCollectionType() == ROOT::kSTLset || proxy.GetCollectionType() == ROOT::kSTLmultiset
4032  || proxy.GetCollectionType() == ROOT::kSTLmap || proxy.GetCollectionType() == ROOT::kSTLmultimap)
4033  {
4034  Long_t increment = proxy.GetIncrement();
4035  sequence->fLoopConfig = new TVectorLoopConfig(increment);
4036  // sequence->fLoopConfig = new TAssocLoopConfig(proxy); */
4037  } else {
4038  sequence->fLoopConfig = new TGenericLoopConfig(&proxy, /* read */ kFALSE);
4039  }
4040  for (UInt_t i = 0; i < ndata; ++i) {
4041  TStreamerElement *element = (TStreamerElement*) info->GetElements()->At(i);
4042  if (!element) {
4043  break;
4044  }
4045  if (element->GetType() < 0) {
4046  // -- Skip an ignored TObject base class.
4047  // Note: The only allowed negative value here is -1, and signifies that Build() has found a TObject
4048  // base class and TClass::IgnoreTObjectStreamer() was called. In this case the compiled version of the
4049  // elements omits the TObject base class element, which has to be compensated for by TTree::Bronch()
4050  // when it is making branches for a split object.
4051  continue;
4052  }
4053  if (element->TestBit(TStreamerElement::kCache) && !element->TestBit(TStreamerElement::kWrite)) {
4054  // Skip element cached for reading purposes.
4055  continue;
4056  }
4057  if (element->GetType() >= TVirtualStreamerInfo::kArtificial && !element->TestBit(TStreamerElement::kWrite)) {
4058  // Skip artificial element used for reading purposes.
4059  continue;
4060  }
4061  TStreamerInfo::TCompInfo *compinfo = sinfo->fCompFull[i];
4062  Int_t asize = element->GetSize();
4063  if (element->GetArrayLength()) {
4064  asize /= element->GetArrayLength();
4065  }
4066  Int_t oldType = element->GetType();
4067  Int_t offset = element->GetOffset();
4068 #if defined(CDJ_NO_COMPILE)
4069  Int_t newType = element->GetNewType();
4070 
4071  if (newType != oldType) {
4072  if (newType > 0) {
4073  if (oldType != TVirtualStreamerInfo::kCounter) {
4074  oldType += TVirtualStreamerInfo::kConv;
4075  }
4076  } else {
4077  oldType += TVirtualStreamerInfo::kSkip;
4078  }
4079  }
4080  if ( IsDefaultVector(proxy)
4081  /*|| (proxy.GetCollectionType() == ROOT::kSTLset || proxy.GetCollectionType() == ROOT::kSTLmultiset
4082  || proxy.GetCollectionType() == ROOT::kSTLmap || proxy.GetCollectionType() == ROOT::kSTLmultimap) */ )
4083  {
4084 
4085  // We can speed up the iteration in case of vector. We also know that all emulated collection are stored internally as a vector.
4086  if (element->TestBit(TStreamerElement::kCache)) {
4087  TConfiguredAction action( GetCollectionWriteAction<VectorLooper>(info,element,oldType,i,compinfo,offset) );
4088  sequence->AddAction( UseCacheVectorLoop, new TConfigurationUseCache(info,action,element->TestBit(TStreamerElement::kRepeat)) );
4089  } else {
4090  sequence->AddAction(GetCollectionWriteAction<VectorLooper>(info,element,oldType,i,compinfo,offset));
4091  }
4092 
4093  // } else if (proxy.GetCollectionType() == ROOT::kSTLset || proxy.GetCollectionType() == ROOT::kSTLmultiset
4094  // || proxy.GetCollectionType() == ROOT::kSTLmap || proxy.GetCollectionType() == ROOT::kSTLmultimap) {
4095  // sequence->AddAction( GenericAssocCollectionAction, new TConfigSTL(info,i,compinfo,offset,0,proxy.GetCollectionClass(),0,0) );
4096  } else {
4097  // The usual collection case.
4098  if (element->TestBit(TStreamerElement::kCache)) {
4099  TConfiguredAction action( GetWriteAction<VectorLooper>(info,element,oldType,i,compinfo,offset) );
4100  sequence->AddAction( UseCacheGenericCollection, new TConfigurationUseCache(info,action,element->TestBit(TStreamerElement::kRepeat)) );
4101  } else {
4102  switch (oldType) {
4103  // read basic types
4104  case TVirtualStreamerInfo::kBool: sequence->AddAction( WriteBasicTypeGenericLoop<Bool_t>, new TConfiguration(info,i,compinfo,offset) ); break;
4105  case TVirtualStreamerInfo::kChar: sequence->AddAction( WriteBasicTypeGenericLoop<Char_t>, new TConfiguration(info,i,compinfo,offset) ); break;
4106  case TVirtualStreamerInfo::kShort: sequence->AddAction( WriteBasicTypeGenericLoop<Short_t>, new TConfiguration(info,i,compinfo,offset) ); break;
4107  case TVirtualStreamerInfo::kInt: sequence->AddAction( WriteBasicTypeGenericLoop<Int_t>, new TConfiguration(info,i,compinfo,offset) ); break;
4108  case TVirtualStreamerInfo::kLong: sequence->AddAction( WriteBasicTypeGenericLoop<Long_t>, new TConfiguration(info,i,compinfo,offset) ); break;
4109  case TVirtualStreamerInfo::kLong64: sequence->AddAction( WriteBasicTypeGenericLoop<Long64_t>, new TConfiguration(info,i,compinfo,offset) ); break;
4110  case TVirtualStreamerInfo::kFloat: sequence->AddAction( WriteBasicTypeGenericLoop<Float_t>, new TConfiguration(info,i,compinfo,offset) ); break;
4111  case TVirtualStreamerInfo::kDouble: sequence->AddAction( WriteBasicTypeGenericLoop<Double_t>, new TConfiguration(info,i,compinfo,offset) ); break;
4112  case TVirtualStreamerInfo::kUChar: sequence->AddAction( WriteBasicTypeGenericLoop<UChar_t>, new TConfiguration(info,i,compinfo,offset) ); break;
4113  case TVirtualStreamerInfo::kUShort: sequence->AddAction( WriteBasicTypeGenericLoop<UShort_t>, new TConfiguration(info,i,compinfo,offset) ); break;
4114  case TVirtualStreamerInfo::kUInt: sequence->AddAction( WriteBasicTypeGenericLoop<UInt_t>, new TConfiguration(info,i,compinfo,offset) ); break;
4115  case TVirtualStreamerInfo::kULong: sequence->AddAction( WriteBasicTypeGenericLoop<ULong_t>, new TConfiguration(info,i,compinfo,offset) ); break;
4116  case TVirtualStreamerInfo::kULong64: sequence->AddAction( WriteBasicTypeGenericLoop<ULong64_t>, new TConfiguration(info,i,compinfo,offset) ); break;
4117  // case TVirtualStreamerInfo::kBits: sequence->AddAction( WriteBasicTypeGenericLoop<BitsMarker>, new TConfiguration(info,i,compinfo,offset) ); break;
4118  case TVirtualStreamerInfo::kFloat16: {
4119  if (element->GetFactor() != 0) {
4120  sequence->AddAction( GenericLooper<WriteBasicType_WithFactor<float> >, new TConfWithFactor(info,i,compinfo,offset,element->GetFactor(),element->GetXmin()) );
4121  } else {
4122  Int_t nbits = (Int_t)element->GetXmin();
4123  if (!nbits) nbits = 12;
4124  sequence->AddAction( GenericLooper<WriteBasicType_NoFactor<float> >, new TConfNoFactor(info,i,compinfo,offset,nbits) );
4125  }
4126  break;
4127  }
4128  case TVirtualStreamerInfo::kDouble32: {
4129  if (element->GetFactor() != 0) {
4130  sequence->AddAction( GenericLooper<WriteBasicType_WithFactor<double> >, new TConfWithFactor(info,i,compinfo,offset,element->GetFactor(),element->GetXmin()) );
4131  } else {
4132  Int_t nbits = (Int_t)element->GetXmin();
4133  if (!nbits) {
4134  sequence->AddAction( GenericLooper<ConvertBasicType<float,double> >, new TConfiguration(info,i,compinfo,offset) );
4135  } else {
4136  sequence->AddAction( GenericLooper<WriteBasicType_NoFactor<double> >, new TConfNoFactor(info,i,compinfo,offset,nbits) );
4137  }
4138  }
4139  break;
4140  }
4141  case TVirtualStreamerInfo::kTNamed: sequence->AddAction( GenericLooper<WriteTNamed >, new TConfiguration(info,i,compinfo,offset) ); break;
4142  // Idea: We should calculate the CanIgnoreTObjectStreamer here and avoid calling the
4143  // Streamer alltogether.
4144  case TVirtualStreamerInfo::kTObject: sequence->AddAction( GenericLooper<WriteTObject >, new TConfiguration(info,i,compinfo,offset) ); break;
4145  case TVirtualStreamerInfo::kTString: sequence->AddAction( GenericLooper<WriteTString >, new TConfiguration(info,i,compinfo,offset) ); break;
4146  default:
4147  sequence->AddAction( GenericCollectionWriteAction, new TConfigSTL(info,i,0 /* the offset will be used from TStreamerInfo */,0,proxy.GetCollectionClass(),0,0) );
4148  break;
4149  }
4150  }
4151  }
4152 #else
4153  if ( IsDefaultVector(proxy)
4154  /*|| (proxy.GetCollectionType() == ROOT::kSTLset || proxy.GetCollectionType() == ROOT::kSTLmultiset
4155  || proxy.GetCollectionType() == ROOT::kSTLmap || proxy.GetCollectionType() == ROOT::kSTLmultimap)*/ )
4156  {
4157  sequence->AddAction( GetCollectionWriteAction<VectorLooper>(info,element,oldType,i,compinfo,offset) );
4158  } else {
4159  // NOTE: TBranch::FillLeavesCollection[Member] is not yet ready to handle the sequence
4160  // as it does not create/use a TStaging as expected ... but then again it might
4161  // not be the right things to expect ...
4162  // sequence->AddAction( GetCollectionWriteAction<GenericLooper>(info,element,oldType,i,compinfo,offset) );
4163  sequence->AddAction( GenericLooper::GenericWrite, new TConfigSTL(info,i,compinfo,0 /* the offset will be used from TStreamerInfo */,0,proxy.GetCollectionClass(),0,0) );
4164  }
4165 #endif
4166  }
4167  return sequence;
4168 }
4169 
4170 void TStreamerInfoActions::TActionSequence::AddToOffset(Int_t delta)
4171 {
4172  // Add the (potentially negative) delta to all the configuration's offset. This is used by
4173  // TBranchElement in the case of split sub-object.
4174 
4175  TStreamerInfoActions::ActionContainer_t::iterator end = fActions.end();
4176  for(TStreamerInfoActions::ActionContainer_t::iterator iter = fActions.begin();
4177  iter != end;
4178  ++iter)
4179  {
4180  if (!iter->fConfiguration->fInfo->GetElements()->At(iter->fConfiguration->fElemId)->TestBit(TStreamerElement::kCache))
4181  iter->fConfiguration->AddToOffset(delta);
4182  }
4183 }
4184 
4185 void TStreamerInfoActions::TActionSequence::SetMissing()
4186 {
4187  // Add the (potentially negative) delta to all the configuration's offset. This is used by
4188  // TBranchElement in the case of split sub-object.
4189 
4190  TStreamerInfoActions::ActionContainer_t::iterator end = fActions.end();
4191  for(TStreamerInfoActions::ActionContainer_t::iterator iter = fActions.begin();
4192  iter != end;
4193  ++iter)
4194  {
4195  if (!iter->fConfiguration->fInfo->GetElements()->At(iter->fConfiguration->fElemId)->TestBit(TStreamerElement::kCache))
4196  iter->fConfiguration->SetMissing();
4197  }
4198 }
4199 
4200 TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::CreateCopy()
4201 {
4202  // Create a copy of this sequence.
4203 
4204  TStreamerInfoActions::TActionSequence *sequence = new TStreamerInfoActions::TActionSequence(fStreamerInfo,fActions.size());
4205 
4206  sequence->fLoopConfig = fLoopConfig ? fLoopConfig->Copy() : 0;
4207 
4208  TStreamerInfoActions::ActionContainer_t::iterator end = fActions.end();
4209  for(TStreamerInfoActions::ActionContainer_t::iterator iter = fActions.begin();
4210  iter != end;
4211  ++iter)
4212  {
4213  TConfiguration *conf = iter->fConfiguration->Copy();
4214  sequence->AddAction( iter->fAction, conf );
4215  }
4216  return sequence;
4217 }
4218 
4219 void TStreamerInfoActions::TActionSequence::AddToSubSequence(TStreamerInfoActions::TActionSequence *sequence,
4220  const TStreamerInfoActions::TIDs &element_ids,
4221  Int_t offset,
4222  TStreamerInfoActions::TActionSequence::SequenceGetter_t create)
4223 {
4224  for(UInt_t id = 0; id < element_ids.size(); ++id) {
4225  if ( element_ids[id].fElemID < 0 ) {
4226  if (element_ids[id].fNestedIDs) {
4227  auto original = create(element_ids[id].fNestedIDs->fInfo,
4228  sequence->fLoopConfig ? sequence->fLoopConfig->GetCollectionProxy() : nullptr,
4229  nullptr);
4230  if (element_ids[id].fNestedIDs->fOnfileObject) {
4231  auto conf = new TConfigurationPushDataCache(element_ids[id].fNestedIDs->fInfo, element_ids[id].fNestedIDs->fOnfileObject, offset);
4232  if ( sequence->fLoopConfig )
4233  sequence->AddAction( PushDataCacheGenericCollection, conf );
4234  else
4235  sequence->AddAction( PushDataCache, conf );
4236  }
4237 
4238  original->AddToSubSequence(sequence, element_ids[id].fNestedIDs->fIDs, element_ids[id].fNestedIDs->fOffset, create);
4239 
4240  if (element_ids[id].fNestedIDs->fOnfileObject)
4241  sequence->AddAction( PopDataCache,
4242  new TConfigurationPushDataCache(element_ids[id].fNestedIDs->fInfo, nullptr, element_ids[id].fNestedIDs->fOffset) );
4243  } else {
4244  TStreamerInfoActions::ActionContainer_t::iterator end = fActions.end();
4245  for(TStreamerInfoActions::ActionContainer_t::iterator iter = fActions.begin();
4246  iter != end;
4247  ++iter)
4248  {
4249  TConfiguration *conf = iter->fConfiguration->Copy();
4250  if (!iter->fConfiguration->fInfo->GetElements()->At(iter->fConfiguration->fElemId)->TestBit(TStreamerElement::kCache))
4251  conf->AddToOffset(offset);
4252  sequence->AddAction( iter->fAction, conf );
4253  }
4254  }
4255  } else {
4256  int localIndex = 0;
4257  TStreamerInfoActions::ActionContainer_t::iterator end = fActions.end();
4258  for(TStreamerInfoActions::ActionContainer_t::iterator iter = fActions.begin();
4259  iter != end;
4260  ++iter) {
4261  // fprintf(stderr, "With element_ids[%d] For %s comparing act[%d/%zu] %d to %d for %p vs %p %s\n",
4262  // id,
4263  // iter->fConfiguration->fInfo->GetName(),
4264  // localIndex, fActions.size(),
4265  // iter->fConfiguration->fElemId,
4266  // (UInt_t)element_ids[id].fElemID, iter->fConfiguration->fInfo,
4267  // element_ids[id].fInfo,
4268  // element_ids[id].fInfo ? element_ids[id].fInfo->GetName() : "nullptr" );
4269  ++localIndex;
4270  if ( iter->fConfiguration->fElemId == (UInt_t)element_ids[id].fElemID ) {
4271  TConfiguration *conf = iter->fConfiguration->Copy();
4272  if (!iter->fConfiguration->fInfo->GetElements()->At(iter->fConfiguration->fElemId)->TestBit(TStreamerElement::kCache))
4273  conf->AddToOffset(offset);
4274  sequence->AddAction( iter->fAction, conf );
4275  }
4276  }
4277  }
4278  }
4279 }
4280 
4281 TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::CreateSubSequence(const TIDs &element_ids, size_t offset,
4282  TStreamerInfoActions::TActionSequence::SequenceGetter_t create)
4283 {
4284  // Create a sequence containing the subset of the action corresponding to the SteamerElement whose ids is contained in the vector.
4285  // 'offset' is the location of this 'class' within the object (address) that will be passed to ReadBuffer when using this sequence.
4286 
4287  TStreamerInfoActions::TActionSequence *sequence = new TStreamerInfoActions::TActionSequence(fStreamerInfo,element_ids.size());
4288 
4289  sequence->fLoopConfig = fLoopConfig ? fLoopConfig->Copy() : 0;
4290 
4291  AddToSubSequence(sequence, element_ids, offset, create);
4292 
4293  return sequence;
4294 }
4295 
4296 TStreamerInfoActions::TActionSequence *TStreamerInfoActions::TActionSequence::CreateSubSequence(const std::vector<Int_t> &element_ids, size_t offset)
4297 {
4298  // Create a sequence containing the subset of the action corresponding to the SteamerElement whose ids is contained in the vector.
4299  // 'offset' is the location of this 'class' within the object (address) that will be passed to ReadBuffer when using this sequence.
4300 
4301  TStreamerInfoActions::TActionSequence *sequence = new TStreamerInfoActions::TActionSequence(fStreamerInfo,element_ids.size());
4302 
4303  sequence->fLoopConfig = fLoopConfig ? fLoopConfig->Copy() : 0;
4304 
4305  for(UInt_t id = 0; id < element_ids.size(); ++id) {
4306  if ( element_ids[id] < 0 ) {
4307  TStreamerInfoActions::ActionContainer_t::iterator end = fActions.end();
4308  for(TStreamerInfoActions::ActionContainer_t::iterator iter = fActions.begin();
4309  iter != end;
4310  ++iter)
4311  {
4312  TConfiguration *conf = iter->fConfiguration->Copy();
4313  if (!iter->fConfiguration->fInfo->GetElements()->At(iter->fConfiguration->fElemId)->TestBit(TStreamerElement::kCache))
4314  conf->AddToOffset(offset);
4315  sequence->AddAction( iter->fAction, conf );
4316  }
4317  } else {
4318  TStreamerInfoActions::ActionContainer_t::iterator end = fActions.end();
4319  for(TStreamerInfoActions::ActionContainer_t::iterator iter = fActions.begin();
4320  iter != end;
4321  ++iter) {
4322  if ( iter->fConfiguration->fElemId == (UInt_t)element_ids[id] ) {
4323  TConfiguration *conf = iter->fConfiguration->Copy();
4324  if (!iter->fConfiguration->fInfo->GetElements()->At(iter->fConfiguration->fElemId)->TestBit(TStreamerElement::kCache))
4325  conf->AddToOffset(offset);
4326  sequence->AddAction( iter->fAction, conf );
4327  }
4328  }
4329  }
4330  }
4331  return sequence;
4332 }
4333 
4334 #if !defined(R__WIN32) && !defined(_AIX)
4335 
4336 #include <dlfcn.h>
4337 
4338 #endif
4339 
4340 typedef void (*voidfunc)();
4341 static const char *R__GetSymbolName(voidfunc func)
4342 {
4343 #if defined(R__WIN32) || defined(__CYGWIN__) || defined(_AIX)
4344  return "not available on this platform";
4345 #if 0
4346  MEMORY_BASIC_INFORMATION mbi;
4347  if (!VirtualQuery (func, &mbi, sizeof (mbi)))
4348  {
4349  return 0;
4350  }
4351 
4352  HMODULE hMod = (HMODULE) mbi.AllocationBase;
4353  static char moduleName[MAX_PATH];
4354 
4355  if (!GetModuleFileNameA (hMod, moduleName, sizeof (moduleName)))
4356  {
4357  return 0;
4358  }
4359  return moduleName;
4360 #endif
4361 #else
4362  Dl_info info;
4363  if (dladdr((void*)func,&info)==0) {
4364  // Not in a known share library, let's give up
4365  return "name not found";
4366  } else {
4367  //fprintf(stdout,"Found address in %s\n",info.dli_fname);
4368  return info.dli_sname;
4369  }
4370 #endif
4371 }
4372 
4373 void TStreamerInfoActions::TActionSequence::Print(Option_t *opt) const
4374 {
4375  // Add the (potentially negative) delta to all the configuration's offset. This is used by
4376  // TTBranchElement in the case of split sub-object.
4377  // If opt contains 'func', also print the (mangled) name of the function that will be executed.
4378 
4379  if (fLoopConfig) {
4380  fLoopConfig->Print();
4381  }
4382  TStreamerInfoActions::ActionContainer_t::const_iterator end = fActions.end();
4383  for(TStreamerInfoActions::ActionContainer_t::const_iterator iter = fActions.begin();
4384  iter != end;
4385  ++iter)
4386  {
4387  iter->fConfiguration->Print();
4388  if (strstr(opt,"func")) {
4389  printf("StreamerInfoAction func: %s\n",R__GetSymbolName((voidfunc)iter->fAction));
4390  }
4391  }
4392 }
4393 
4394