Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
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"
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 "TClassEdit.h"
25#include "TProcessID.h"
26#include "TFile.h"
27
29
30// More possible optimizations:
31// Avoid call the virtual version of TBuffer::ReadInt and co.
32// Merge the Reading of the version and the looking up or the StreamerInfo
33// Avoid if (bytecnt) inside the CheckByteCount routines and avoid multiple (mostly useless nested calls)
34// Try to avoid if statement on onfile class being set (TBufferFile::ReadClassBuffer).
35
36using namespace TStreamerInfoActions;
37
38#ifdef _AIX
39# define INLINE_TEMPLATE_ARGS
40#else
41# define INLINE_TEMPLATE_ARGS inline
42#endif
43
44
46{
47 enum class EMode
48 {
49 kRead,
50 kWrite
51 };
52
54 {
55 const auto props = proxy.GetProperties();
56 const bool isVector = proxy.GetCollectionType() == ROOT::kSTLvector;
59
60 return isEmulated || (isVector && hasDefaultAlloc);
61 }
62
63 template <typename From>
65 typedef From Value_t;
66 };
67
68 template <typename From>
70 typedef From Value_t;
71 };
72
73 struct BitsMarker {
74 typedef UInt_t Value_t;
75 };
76
78 {
79 // Add the (potentially negative) delta to all the configuration's offset. This is used by
80 // TBranchElement in the case of split sub-object.
81
83 fOffset += delta;
84 }
85
87 {
88 // Add the (potentially negative) delta to all the configuration's offset. This is used by
89 // TBranchElement in the case of split sub-object.
90
92 }
93
95 {
96 // Inform the user what we are about to stream.
97
98 // Idea, we should find a way to print the name of the function
100 }
101
103 {
104 // Inform the user what we are about to stream.
105
109 aElement->GetSequenceType(sequenceType);
110
111 printf("StreamerInfoAction, class:%s, name=%s, fType[%d]=%d,"
112 " %s, offset=%d (%s), elemnId=%d \n",
113 info->GetClass()->GetName(), aElement->GetName(), fElemId, fCompInfo->fType,
114 aElement->ClassName(), fOffset, sequenceType.Data(), fElemId);
115 }
116
118 {
119 // Inform the user what we are about to stream.
120
121 if (gDebug > 1) {
122 // Idea: We should print the name of the action function.
126 aElement->GetSequenceType(sequenceType);
127
128 printf("StreamerInfoAction, class:%s, name=%s, fType[%d]=%d,"
129 " %s, bufpos=%d, arr=%p, offset=%d (%s)\n",
130 info->GetClass()->GetName(), aElement->GetName(), fElemId, fCompInfo->fType,
131 aElement->ClassName(), buf.Length(), addr, fOffset, sequenceType.Data());
132 }
133 }
134
136 {
137 // Inform the user what we are about to stream.
138
139 printf("TLoopConfiguration: unconfigured\n");
140 }
141
142
144 // Configuration of action using the legacy code.
145 // Mostly to cancel out the PrintDebug.
146 public:
148 void PrintDebug(TBuffer &, void *) const override {
149 // Since we call the old code, it will print the debug statement.
150 }
151
152 TConfiguration *Copy() override { return new TGenericConfiguration(*this); }
153 };
154
156 // Configuration of action handling kBits.
157 // In this case we need to know both the location
158 // of the member (fBits) and the start of the object
159 // (its TObject part to be exact).
160
161 Int_t fObjectOffset; // Offset of the TObject part within the object
162
164 void PrintDebug(TBuffer &, void *) const override
165 {
169 aElement->GetSequenceType(sequenceType);
170
171 printf("StreamerInfoAction, class:%s, name=%s, fType[%d]=%d,"
172 " %s, offset=%d (%s)\n",
173 info->GetClass()->GetName(), aElement->GetName(), fElemId, fCompInfo->fType,
174 aElement->ClassName(), fOffset, sequenceType.Data());
175 }
176
177 void AddToOffset(Int_t delta) override
178 {
179 // Add the (potentially negative) delta to all the configuration's offset. This is used by
180 // TBranchElement in the case of split sub-object.
181
183 fOffset += delta;
184 fObjectOffset = 0;
185 }
186
187 void SetMissing() override
188 {
190 fObjectOffset = 0;
191 }
192
193 TConfiguration *Copy() override { return new TBitsConfiguration(*this); }
194
195 };
196
209
211 {
212 std::unique_ptr<TStreamerInfoActions::TActionSequence> fActions;
213
215 std::unique_ptr<TStreamerInfoActions::TActionSequence> actions) :
217 fActions(std::move(actions))
218 {}
219
223
224 void AddToOffset(Int_t delta) override
225 {
226 // Add the (potentially negative) delta to all the configuration's offset. This is used by
227 // TBranchElement in the case of split sub-object.
228
230 fOffset += delta;
231 if (fActions)
232 fActions->AddToOffset(delta);
233 }
234 }
235
236 TConfiguration *Copy() override { return new TConfSubSequence(*this); };
237 };
238
240 bool fIsPtrPtr = false; // Which are we, an array of objects or an array of pointers to objects?
241
246
247 TConfiguration *Copy() override { return new TConfStreamerLoop(*this); };
248 };
249
251 {
252 char *obj = (char*)addr;
254 return ((TStreamerInfo*)conf->fInfo)->ReadBuffer(buf, &obj, &(conf->fCompInfo), /*first*/ 0, /*last*/ 1, /*narr*/ 1, config->fOffset, 2);
255 }
256
258 {
259 char *obj = (char*)addr;
261 return ((TStreamerInfo*)conf->fInfo)->WriteBufferAux(buf, &obj, &(conf->fCompInfo), /*first*/ 0, /*last*/ 1, /*narr*/ 1, config->fOffset, 2);
262 }
263
264 template <typename T>
266 {
267 T *x = (T*)( ((char*)addr) + config->fOffset );
268 // Idea: Implement buf.ReadBasic/Primitive to avoid the return value
269 buf >> *x;
270 return 0;
271 }
272
273 void HandleReferencedTObject(TBuffer &buf, void *addr, const TConfiguration *config) {
276 buf >> pidf;
277 pidf += buf.GetPidOffset();
278 TProcessID *pid = buf.ReadProcessID(pidf);
279 if (pid!=0) {
280 TObject *obj = (TObject*)( ((char*)addr) + conf->fObjectOffset);
281 UInt_t gpid = pid->GetUniqueID();
282 UInt_t uid;
283 if (gpid>=0xff) {
284 uid = obj->GetUniqueID() | 0xff000000;
285 } else {
286 uid = ( obj->GetUniqueID() & 0xffffff) + (gpid<<24);
287 }
288 obj->SetUniqueID(uid);
289 pid->PutObjectWithID(obj);
290 }
291 }
292
293 inline Int_t ReadViaExtStreamer(TBuffer &buf, void *addr, const TConfiguration *config)
294 {
295 void *x = (void *)(((char *)addr) + config->fOffset);
297 (*pstreamer)(buf, x, config->fCompInfo->fLength);
298 return 0;
299 }
300
301 inline Int_t WriteViaExtStreamer(TBuffer &buf, void *addr, const TConfiguration *config)
302 {
303 void *x = (void *)(((char *)addr) + config->fOffset);
305 (*pstreamer)(buf, x, config->fCompInfo->fLength);
306 return 0;
307 }
308
310 {
311 UInt_t start, count;
312 /* Version_t v = */ buf.ReadVersion(&start, &count, config->fInfo->IsA());
313
314 ReadViaExtStreamer(buf, addr, config);
315
316 buf.CheckByteCount(start, count, config->fCompInfo->fElem->GetFullName());
317 return 0;
318 }
319
321 {
322 UInt_t pos = buf.WriteVersion(config->fInfo->IsA(), kTRUE);
323
324 WriteViaExtStreamer(buf, addr, config);
325
326 buf.SetByteCount(pos, kTRUE);
327 return 0;
328 }
329
330 // Read a full object objectwise including reading the version and
331 // selecting any conversion.
333 {
334 auto conf = (TConfObject*)config;
335 auto memoryClass = conf->fInMemoryClass;
336 auto onfileClass = conf->fOnfileClass;
337
338 char * const where = (((char*)addr)+config->fOffset);
340 return 0;
341 }
342
343 // Write a full object objectwise including reading the version and
344 // selecting any conversion.
346 {
347 auto conf = (TConfObject*)config;
348 [[maybe_unused]] auto memoryClass = conf->fInMemoryClass;
349 auto onfileClass = conf->fOnfileClass;
350 assert((memoryClass == nullptr || memoryClass == onfileClass)
351 && "Need to new TBufferFile::WriteClassBuffer overload to support this case");
352
353 char * const where = (((char*)addr)+config->fOffset);
355 return 0;
356 }
357
358 template <>
360 {
361 UInt_t *x = (UInt_t*)( ((char*)addr) + config->fOffset );
362 // Idea: Implement buf.ReadBasic/Primitive to avoid the return value
363 // Idea: This code really belongs inside TBuffer[File]
364 const UInt_t isonheap = *x & TObject::kIsOnHeap; // Record how this instance was actually allocated.
365 buf >> *x;
366 *x |= isonheap | TObject::kNotDeleted; // by definition de-serialized object are not yet deleted.
367
368 if ((*x & kIsReferenced) != 0) {
369 HandleReferencedTObject(buf,addr,config);
370 }
371 return 0;
372 }
373
374 template <typename T>
376 {
377 buf << T{0};
378 return 0;
379 }
380
381 template <typename T>
383 {
384 T *x = (T *)(((char *)addr) + config->fOffset);
385 // Idea: Implement buf.ReadBasic/Primitive to avoid the return value
386 buf << *x;
387 return 0;
388 }
389
390 template <typename Onfile, typename Memory>
392 static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *addr, const TConfiguration *config)
393 {
394 // Simple conversion from a 'From' on disk to a 'To' in memory.
395 Onfile temp;
396 temp = (Onfile)(*(Memory*)( ((char*)addr) + config->fOffset ));
397 buf << temp;
398 return 0;
399 }
400 };
401
403 {
404 void *x = (void *)(((char *)addr) + config->fOffset);
405 // Idea: Implement buf.ReadBasic/Primitive to avoid the return value
407 return 0;
408 }
409
411 {
412 void *x = (void *)(((char *)addr) + config->fOffset);
413 // Idea: Implement buf.ReadBasic/Primitive to avoid the return value
415 return 0;
416 }
417
419 {
420 void *x = (void *)(((char *)addr) + config->fOffset);
421 // Idea: Implement buf.ReadBasic/Primitive to avoid the return value
422 ((TBufferText *)&buf)->WriteBaseClass(x, (TStreamerBase *)config->fCompInfo->fElem);
423 return 0;
424 }
425
427 {
428 void *x = (void *)(((char *)addr) + config->fOffset);
429 buf.ReadFastArray(x, config->fCompInfo->fClass, config->fCompInfo->fLength, config->fCompInfo->fStreamer);
430 return 0;
431 }
432
434 {
435 void *x = (void *)(((char *)addr) + config->fOffset);
437 return 0;
438 }
439
441 {
442 void *x = (void *)(((char *)addr) + config->fOffset);
443 // Idea: Implement buf.ReadBasic/Primitive to avoid the return value
444 ((TBufferText *)&buf)->ReadBaseClass(x, (TStreamerBase *)config->fCompInfo->fElem);
445 return 0;
446 }
447
449 {
450 // action required to call custom code for TObject as base class
451 void *x = (void *)(((char *)addr) + config->fOffset);
453 return 0;
454 }
455
457 {
458 void *x = (void *)(((char *)addr) + config->fOffset);
460 return 0;
461 }
462
464 {
465 buf.WriteFloat16(addr, const_cast<TStreamerElement*>(elem));
466 }
467
469 {
470 buf.WriteDouble32(addr, const_cast<TStreamerElement*>(elem));
471 }
472
474 {
475 TClass *cl = config->fCompInfo->fClass;
477 UInt_t ioffset = config->fOffset;
478
479 UInt_t pos = buf.WriteVersion(config->fInfo->IsA(), kTRUE);
480
481 // use same method which is used in kSTL
482 buf.WriteFastArray((void **)((char *)addr + ioffset), cl, config->fCompInfo->fLength, kFALSE, pstreamer);
483
484 buf.SetByteCount(pos, kTRUE);
485 return 0;
486 }
487
489 {
490 TClass *cle = config->fCompInfo->fClass;
493 UInt_t ioffset = config->fOffset;
494 UInt_t start, count;
495 /* Version_t vers = */ buf.ReadVersion(&start, &count, cle);
496
497 // use same method which is used in kSTL
498 buf.ReadFastArray((void **)((char *)addr + ioffset), cle, config->fCompInfo->fLength, kFALSE, pstreamer);
499 buf.CheckByteCount(start, count, aElement->GetFullName());
500 return 0;
501 }
502
504 // Configuration object for the Float16/Double32 where a factor has been specified.
505 public:
509 TConfiguration *Copy() override { return new TConfWithFactor(*this); }
510 };
511
512 template <typename T>
514 {
515 // Stream a Float16 or Double32 where a factor has been specified.
516 //a range was specified. We read an integer and convert it back to a double.
517
519 buf.ReadWithFactor((T*)( ((char*)addr) + config->fOffset ), conf->fFactor, conf->fXmin);
520 return 0;
521 }
522
524 // Configuration object for the Float16/Double32 where a factor has been specified.
525 public:
528 TConfiguration *Copy() override { return new TConfNoFactor(*this); }
529 };
530
531 template <typename T>
533 {
534 // Stream a Float16 or Double32 where a factor has not been specified.
535
536 TConfNoFactor *conf = (TConfNoFactor *)config;
537 Int_t nbits = conf->fNbits;
538
539 buf.ReadWithNbits( (T*)( ((char*)addr) + config->fOffset ), nbits );
540 return 0;
541 }
542
544 {
545 // Read in a TString object.
546
547 // Idea: We could separate the TString Streamer in its two parts and
548 // avoid the if (buf.IsReading()) and try having it inlined.
549 ((TString*)(((char*)addr)+config->fOffset))->TString::Streamer(buf);
550 return 0;
551 }
552
553 inline Int_t WriteTString(TBuffer &buf, void *addr, const TConfiguration *config)
554 {
555 // Read in a TString object.
556
557 // Idea: We could separate the TString Streamer in its two parts and
558 // avoid the if (buf.IsReading()) and try having it inlined.
559 ((TString*)(((char*)addr)+config->fOffset))->TString::Streamer(buf);
560 return 0;
561 }
562
564 {
565 // Read in a TObject object part.
566
567 // Idea: We could separate the TObject Streamer in its two parts and
568 // avoid the if (buf.IsReading()).
569 ((TObject*)(((char*)addr)+config->fOffset))->TObject::Streamer(buf);
570 return 0;
571 }
572
573 inline Int_t WriteTObject(TBuffer &buf, void *addr, const TConfiguration *config)
574 {
575 // Read in a TObject object part.
576
577 // Idea: We could separate the TObject Streamer in its two parts and
578 // avoid the if (buf.IsReading()).
579 ((TObject*)(((char*)addr)+config->fOffset))->TObject::Streamer(buf);
580 return 0;
581 }
582
584 {
585 // Read in a TNamed object part.
586 // Since the TNamed streamer is solely delegating back to the StreamerInfo we
587 // can skip the streamer.
588
589 // Idea: We could extract the code from ReadClassBuffer and avoid one function
590 // code.
591 static const TClass *TNamed_cl = TNamed::Class();
592 return buf.ReadClassBuffer(TNamed_cl,(((char*)addr)+config->fOffset));
593 }
594
595 inline Int_t WriteTNamed(TBuffer &buf, void *addr, const TConfiguration *config)
596 {
597 // Read in a TNamed object part.
598 // Since the TNamed streamer is solely delegating back to the StreamerInfo we
599 // can skip the streamer.
600
601 // Idea: We could extract the code from ReadClassBuffer and avoid one function
602 // code.
603 static const TClass *TNamed_cl = TNamed::Class();
604 return buf.WriteClassBuffer(TNamed_cl,(((char*)addr)+config->fOffset));
605 }
606
607 class TConfigSTL : public TConfiguration {
608 // Configuration object for the kSTL case
609 private:
610 void Init(bool read) {
612 if (proxy) {
613 fCreateIterators = proxy->GetFunctionCreateIterators(read);
614 fCopyIterator = proxy->GetFunctionCopyIterator();
615 fDeleteIterator = proxy->GetFunctionDeleteIterator();
616 fDeleteTwoIterators = proxy->GetFunctionDeleteTwoIterators();
617 if (proxy->HasPointers()) {
619 } else {
620 fNext = proxy->GetFunctionNext(read);
621 }
622 }
623 }
624
625 public:
626 TClass *fOldClass; // Class of the content on file
627 TClass *fNewClass; // Class of the content in memory.
629 const char *fTypeName; // Type name of the member as typed by ther user.
630 Bool_t fIsSTLBase; // aElement->IsBase() && aElement->IsA()!=TStreamerBase::Class()
631
637
638
642
646
650
654
655 TConfiguration *Copy() override { return new TConfigSTL(*this); }
656 };
657
659 // Configuration object for the Float16/Double32 where a factor has been specified.
660 public:
664 TConfiguration *Copy() override { return new TConfSTLWithFactor(*this); }
665 };
666
668 // Configuration object for the Float16/Double32 where a factor has been specified.
669 public:
672 TConfiguration *Copy() override { return new TConfSTLNoFactor(*this); }
673 };
674
676 // Base class of the Configurations used in member wise streaming.
677 protected:
678 public:
679 Long_t fIncrement; // Either a value to increase the cursor by and
680 public:
682 //virtual void PrintDebug(TBuffer &buffer, void *);
683 ~TVectorLoopConfig() override {};
684 void Print() const override
685 {
686 printf("TVectorLoopConfig: increment=%ld\n",fIncrement);
687 }
688
689 void* GetFirstAddress(void *start, const void * /* end */) const override
690 {
691 // Return the address of the first element of the collection.
692
693 return start;
694 }
695
696 TLoopConfiguration* Copy() const override { return new TVectorLoopConfig(*this); }
697 };
698
700 // Base class of the Configurations used in member wise streaming.
701 public:
703 //virtual void PrintDebug(TBuffer &buffer, void *);
704 ~TAssocLoopConfig() override {};
705 void Print() const override
706 {
707 printf("TAssocLoopConfig: proxy=%s\n",fProxy->GetCollectionClass()->GetName());
708 }
709 TLoopConfiguration* Copy() const override { return new TAssocLoopConfig(*this); }
710
711 void* GetFirstAddress(void *start, const void * /* end */) const override
712 {
713 // Return the address of the first element of the collection.
714
715 R__ASSERT(0);
716// char iterator[TVirtualCollectionProxy::fgIteratorArenaSize];
717// void *iter = genloopconfig->fCopyIterator(&iterator,start_collection);
718// arr0 = genloopconfig->fNext(iter,end_collection);
719// if (iter != &iterator[0]) {
720// genloopconfig->fDeleteIterator(iter);
721// }
722 return start;
723 }
724 };
725
727 // Configuration object for the generic case of member wise streaming looping.
728 private:
742 public:
746
751 ~TGenericLoopConfig() override {};
752 void Print() const override
753 {
754 printf("TGenericLoopConfig: proxy=%s\n",fProxy->GetCollectionClass()->GetName());
755 }
756 TLoopConfiguration* Copy() const override { return new TGenericLoopConfig(*this); }
757
758 void* GetFirstAddress(void *start_collection, const void *end_collection) const override
759 {
760 // Return the address of the first element of the collection.
761
763 void *iter = fCopyIterator(&iterator,start_collection);
764 void *arr0 = fNext(iter,end_collection);
765 if (iter != &iterator[0]) {
766 fDeleteIterator(iter);
767 }
768 return arr0;
769 }
770 };
771
773 {
774 // Collection was saved member-wise
775
776 TConfigSTL *config = (TConfigSTL*)conf;
778
779 if( vers >= 8 ) {
780
781 TClass *oldClass = config->fOldClass;
782
783 TVirtualCollectionProxy *oldProxy = oldClass ? oldClass->GetCollectionProxy() : nullptr;
784 if (!oldProxy) {
785 // Missing information, broken file ... give up
786 return;
787 }
788 TClass *valueClass = oldProxy->GetValueClass();
790
793 buf.ReadInt(nobjects);
794 void* alternative = oldProxy->Allocate(nobjects,true);
795 if (nobjects) {
796 TActionSequence *actions = oldProxy->GetReadMemberWiseActions( vClVersion );
797
800 void *begin = &(startbuf[0]);
801 void *end = &(endbuf[0]);
802 config->fCreateIterators(alternative, &begin, &end, oldProxy);
803 // We can not get here with a split vector of pointer, so we can indeed assume
804 // that actions->fConfiguration != null.
805 buf.ApplySequence(*actions, begin, end);
806 if (begin != &(startbuf[0])) {
807 // assert(end != endbuf);
808 config->fDeleteTwoIterators(begin,end);
809 }
810 }
811 oldProxy->Commit(alternative);
812
813 } else {
814
815 TClass *oldClass = config->fOldClass;
816
817 TVirtualCollectionProxy *oldProxy = oldClass ? oldClass->GetCollectionProxy() : nullptr;
818 if (!oldProxy) {
819 // Missing information, broken file ... give up
820 return;
821 }
822
825 buf.ReadInt(nobjects);
826 void* env = oldProxy->Allocate(nobjects,true);
827
828 if (nobjects || vers < 7 ) {
829 // coverity[dereference] since this is a member streaming action by definition the collection contains objects.
830 TStreamerInfo *subinfo = (TStreamerInfo*)oldProxy->GetValueClass()->GetStreamerInfo( 0 );
831
832 subinfo->ReadBufferSTL(buf, oldProxy, nobjects, /* offset */ 0, /* v7 */ kFALSE);
833 }
834 oldProxy->Commit(env);
835 }
836 }
837
839 {
840 // Collection was saved member-wise
841
842 TConfigSTL *config = (TConfigSTL*)conf;
844
845 if( vers >= 8 ) {
846
847 TClass *oldClass = config->fOldClass;
848
849 TVirtualCollectionProxy *oldProxy = oldClass ? oldClass->GetCollectionProxy() : nullptr;
850 if (!oldProxy) {
851 // Missing information, broken file ... give up
852 return;
853 }
854 TClass *valueClass = oldProxy->GetValueClass();
856
857 TActionSequence *actions = oldProxy->GetReadMemberWiseActions( vClVersion );
858
859 int objectSize = oldClass->Size();
860 char *obj = (char*)addr;
861 char *endobj = obj + conf->fLength*objectSize;
862
863 for(; obj<endobj; obj+=objectSize) {
865 buf.ReadInt(nobjects);
867 void* alternative = oldProxy->Allocate(nobjects,true);
868 if (nobjects) {
871 void *begin = &(startbuf[0]);
872 void *end = &(endbuf[0]);
873 config->fCreateIterators(alternative, &begin, &end, oldProxy);
874 // We can not get here with a split vector of pointer, so we can indeed assume
875 // that actions->fConfiguration != null.
876 buf.ApplySequence(*actions, begin, end);
877 if (begin != &(startbuf[0])) {
878 // assert(end != endbuf);
879 config->fDeleteTwoIterators(begin,end);
880 }
881 }
882 oldProxy->Commit(alternative);
883 }
884
885 } else {
886
887 TClass *oldClass = config->fOldClass;
888
889 TVirtualCollectionProxy *oldProxy = oldClass ? oldClass->GetCollectionProxy() : nullptr;
890 if (!oldProxy) {
891 // Missing information, broken file ... give up
892 return;
893 }
894
895 int objectSize = oldClass->Size();
896 char *obj = (char*)addr;
897 char *endobj = obj + conf->fLength*objectSize;
898
899 for(; obj<endobj; obj+=objectSize) {
902 buf.ReadInt(nobjects);
903 void* env = oldProxy->Allocate(nobjects,true);
904
905 if (nobjects || vers < 7 ) {
906 // coverity[dereference] since this is a member streaming action by definition the collection contains objects.
907 TStreamerInfo *subinfo = (TStreamerInfo*)oldProxy->GetValueClass()->GetStreamerInfo( 0 );
908
909 subinfo->ReadBufferSTL(buf, oldProxy, nobjects, /* offset */ 0, /* v7 */ kFALSE);
910 }
911 oldProxy->Commit(env);
912 }
913 }
914 }
915
917 {
918 // Collection was saved member-wise
919
920 TConfigSTL *config = (TConfigSTL*)conf;
921
923
924 TClass *newClass = config->fNewClass;
925 TClass *oldClass = config->fOldClass;
926
927 if( vers < 8 ) {
928 Error( "ReadSTLMemberWiseChangedClass", "Unfortunately, version %d of TStreamerInfo (used in %s) did not record enough information to convert a %s into a %s.",
929 vers, buf.GetParent() ? buf.GetParent()->GetName() : "memory/socket", oldClass ? oldClass->GetName() : "(could not find the origin TClass)", newClass ? newClass->GetName() : "(could not find the destination TClass)" );
930 } else if (newClass && oldClass){
931
932 Version_t vClVersion = buf.ReadVersionForMemberWise( oldClass->GetCollectionProxy()->GetValueClass() );
933
934 TVirtualCollectionProxy *newProxy = newClass->GetCollectionProxy();
935 TVirtualCollectionProxy *oldProxy = oldClass->GetCollectionProxy();
936
939 buf.ReadInt(nobjects);
940 void* alternative = newProxy->Allocate(nobjects,true);
941 if (nobjects) {
942 TActionSequence *actions = newProxy->GetConversionReadMemberWiseActions( oldProxy->GetValueClass(), vClVersion );
945 void *begin = &(startbuf[0]);
946 void *end = &(endbuf[0]);
947 config->fCreateIterators( alternative, &begin, &end, newProxy);
948 // We can not get here with a split vector of pointer, so we can indeed assume
949 // that actions->fConfiguration != null.
950 buf.ApplySequence(*actions, begin, end);
951 if (begin != &(startbuf[0])) {
952 // assert(end != endbuf);
953 config->fDeleteTwoIterators(begin,end);
954 }
955 }
956 newProxy->Commit(alternative);
957 }
958 }
959
961 {
962 // Collection was saved member-wise
963
964 TConfigSTL *config = (TConfigSTL*)conf;
965
967
968 TClass *newClass = config->fNewClass;
969 TClass *oldClass = config->fOldClass;
970
971 if( vers < 8 ) {
972 Error( "ReadSTLMemberWiseChangedClass", "Unfortunately, version %d of TStreamerInfo (used in %s) did not record enough information to convert a %s into a %s.",
973 vers, buf.GetParent() ? buf.GetParent()->GetName() : "memory/socket", oldClass ? oldClass->GetName() : "(could not find the origin TClass)", newClass ? newClass->GetName() : "(could not find the destination TClass)" );
974 } else if (newClass && oldClass) {
975
976 Version_t vClVersion = buf.ReadVersionForMemberWise( oldClass->GetCollectionProxy()->GetValueClass() );
977
978 TVirtualCollectionProxy *newProxy = newClass->GetCollectionProxy();
979 TVirtualCollectionProxy *oldProxy = oldClass->GetCollectionProxy();
980
981 int objectSize = newClass->Size();
982 char *obj = (char*)addr;
983 char *endobj = obj + conf->fLength*objectSize;
984
985 for(; obj<endobj; obj+=objectSize) {
988 buf.ReadInt(nobjects);
989 void* alternative = newProxy->Allocate(nobjects,true);
990 if (nobjects) {
991 TActionSequence *actions = newProxy->GetConversionReadMemberWiseActions( oldProxy->GetValueClass(), vClVersion );
994 void *begin = &(startbuf[0]);
995 void *end = &(endbuf[0]);
996 config->fCreateIterators( alternative, &begin, &end, newProxy);
997 // We can not get here with a split vector of pointer, so we can indeed assume
998 // that actions->fConfiguration != null.
999 buf.ApplySequence(*actions, begin, end);
1000 if (begin != &(startbuf[0])) {
1001 // assert(end != endbuf);
1002 config->fDeleteTwoIterators(begin,end);
1003 }
1004 }
1005 newProxy->Commit(alternative);
1006 }
1007 }
1008 }
1009
1011 {
1012 TConfigSTL *config = (TConfigSTL*)conf;
1013 // Idea: This needs to be unrolled, it currently calls the TGenCollectionStreamer ....
1014 buf.ReadFastArray(addr,config->fNewClass,conf->fLength,(TMemberStreamer*)0,config->fOldClass);
1015 }
1017 {
1018 TConfigSTL *config = (TConfigSTL*)conf;
1019 (*config->fStreamer)(buf,addr,conf->fLength);
1020 }
1022 {
1023 // case of old TStreamerInfo
1024
1025 TConfigSTL *config = (TConfigSTL*)conf;
1026 // Backward compatibility. Some TStreamerElement's where without
1027 // Streamer but were not removed from element list
1028 if (config->fIsSTLBase || vers == 0) {
1029 buf.SetBufferOffset(start); //there is no byte count
1030 }
1031 // Idea: This needs to be unrolled, it currently calls the TGenCollectionStreamer ....
1032 buf.ReadFastArray(addr,config->fNewClass,conf->fLength,(TMemberStreamer*)0,config->fOldClass);
1033 }
1035 {
1036 // case of old TStreamerInfo
1037
1038 TConfigSTL *config = (TConfigSTL*)conf;
1039 // Backward compatibility. Some TStreamerElement's where without
1040 // Streamer but were not removed from element list
1041 if (config->fIsSTLBase || vers == 0) {
1042 buf.SetBufferOffset(start); //there is no byte count
1043 }
1044 (*config->fStreamer)(buf,addr,conf->fLength);
1045 }
1046
1047 // To Upgrade this to WriteSTLMemberWiseChangedClass (see ReadSTLMemberWiseChangedClass)
1048 // we would need to a TVirtualCollectionProxy::GetConversionWriteMemberWiseActions
1050 {
1051 // Collection was saved member-wise
1052 // newClass -> in memory representation
1053 // oldClass -> onfile representation
1054
1055 TConfigSTL *config = (TConfigSTL*)conf;
1056 TClass *newClass = config->fNewClass;
1057 TClass *onfileClass = config->fOldClass;
1058
1059 // Until the writing of TVirtualCollectionProxy::GetConversionWriteMemberWiseActions
1061 "Class level transformation while writing is not yet supported");
1062
1063 if (newClass && onfileClass) {
1064
1065 buf.WriteVersion( onfileClass->GetCollectionProxy()->GetValueClass(), kFALSE );
1066
1067 TVirtualCollectionProxy *newProxy = newClass->GetCollectionProxy();
1068 TVirtualCollectionProxy *onfileProxy = onfileClass->GetCollectionProxy();
1069
1071 Int_t nobjects = newProxy->Size();
1072 buf.WriteInt(nobjects);
1073 if (nobjects) {
1074 TActionSequence *actions = onfileProxy->GetWriteMemberWiseActions();
1077 void *begin = &(startbuf[0]);
1078 void *end = &(endbuf[0]);
1079 config->fCreateIterators( addr, &begin, &end, newProxy);
1080 // We can not get here with a split vector of pointer, so we can indeed assume
1081 // that actions->fConfiguration != null.
1082 buf.ApplySequence(*actions, begin, end);
1083 if (begin != &(startbuf[0])) {
1084 // assert(end != endbuf);
1085 config->fDeleteTwoIterators(begin,end);
1086 }
1087 }
1088 }
1089 }
1090
1091 // This routine could/should be merge with WriteSTLMemberWise, the only difference
1092 // is the for loop over the objects. We are not using this version for the case
1093 // where `conf->fLength is 1` as we know this information at StreamerInfo build time
1094 // and thus we can avoid the 'waste' of CPU cycles involved in doing a loop of length 1
1096 {
1097 // Collection was saved member-wise
1098 // newClass -> in memory representation
1099 // oldClass -> onfile representation
1100
1101 TConfigSTL *config = (TConfigSTL*)conf;
1102 TClass *newClass = config->fNewClass;
1103 TClass *onfileClass = config->fOldClass;
1104
1105 // Until the writing of TVirtualCollectionProxy::GetConversionWriteMemberWiseActions
1107 "Class level transformation while writing is not yet supported");
1108
1109 if (newClass && onfileClass) {
1110
1111 buf.WriteVersion( onfileClass->GetCollectionProxy()->GetValueClass(), kFALSE );
1112
1113 TVirtualCollectionProxy *newProxy = newClass->GetCollectionProxy();
1114 TVirtualCollectionProxy *onfileProxy = onfileClass->GetCollectionProxy();
1115
1116 int objectSize = newClass->Size();
1117 char *obj = (char*)addr;
1118 char *endobj = obj + conf->fLength * objectSize;
1119
1120 for (; obj < endobj; obj += objectSize) {
1122 Int_t nobjects = newProxy->Size();
1123 buf.WriteInt(nobjects);
1124 if (nobjects) {
1125 TActionSequence *actions = onfileProxy->GetWriteMemberWiseActions();
1128 void *begin = &(startbuf[0]);
1129 void *end = &(endbuf[0]);
1130 config->fCreateIterators( addr, &begin, &end, newProxy);
1131 // We can not get here with a split vector of pointer, so we can indeed assume
1132 // that actions->fConfiguration != null.
1133 buf.ApplySequence(*actions, begin, end);
1134 if (begin != &(startbuf[0])) {
1135 // assert(end != endbuf);
1136 config->fDeleteTwoIterators(begin,end);
1137 }
1138 }
1139 }
1140 }
1141 }
1142
1144 {
1145 TConfigSTL *config = (TConfigSTL*)conf;
1146 // Idea: This needs to be unrolled, it currently calls the TGenCollectionStreamer ....
1147 buf.WriteFastArray(addr,config->fNewClass,conf->fLength,(TMemberStreamer*)0);
1148 }
1150 {
1151 TConfigSTL *config = (TConfigSTL*)conf;
1152 (*config->fStreamer)(buf,addr,conf->fLength);
1153 }
1154
1155 template <void (*memberwise)(TBuffer&,void *,const TConfiguration*, Version_t),
1156 void (*objectwise)(TBuffer&,void *,const TConfiguration*, Version_t, UInt_t)>
1158 {
1159 TConfigSTL *config = (TConfigSTL*)conf;
1160 UInt_t start, count;
1161 Version_t vers = buf.ReadVersion(&start, &count, config->fOldClass);
1163 memberwise(buf,((char*)addr)+config->fOffset,config, vers);
1164 } else {
1165 objectwise(buf,((char*)addr)+config->fOffset,config, vers, start);
1166 }
1167 buf.CheckByteCount(start,count,config->fTypeName);
1168 return 0;
1169 }
1170
1171 template <void (*memberwise)(TBuffer&,void *,const TConfiguration*),
1172 void (*objectwise)(TBuffer&,void *,const TConfiguration*)>
1174 {
1175 TConfigSTL *config = (TConfigSTL*)conf;
1176 UInt_t start;
1177 TClass *onfileClass = config->fOldClass;
1179 TVirtualCollectionProxy *proxy = onfileClass->GetCollectionProxy();
1180 TClass* vClass = proxy ? proxy->GetValueClass() : 0;
1181
1182 // See test in TStreamerInfo::kSTL case in TStreamerInfoWriteBuffer.cxx
1184 && proxy && vClass
1185 && config->fInfo->GetStreamMemberWise() && onfileClass->CanSplit()
1186 && !(strspn(aElement->GetTitle(),"||") == 2)
1187 && !(vClass->HasCustomStreamerMember()) )
1188 {
1189 start = buf.WriteVersionMemberWise(config->fInfo->IsA(), kTRUE);
1190 memberwise(buf, ((char *)addr) + config->fOffset, config);
1191 } else {
1192 start = buf.WriteVersion(config->fInfo->IsA(), kTRUE);
1193 objectwise(buf, ((char *)addr) + config->fOffset, config);
1194 }
1195 buf.SetByteCount(start);
1196 return 0;
1197 }
1198
1199 template <typename From, typename To>
1201 static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *addr, const TConfiguration *config)
1202 {
1203 // Simple conversion from a 'From' on disk to a 'To' in memory.
1204 From temp;
1205 buf >> temp;
1206 *(To*)( ((char*)addr) + config->fOffset ) = (To)temp;
1207 return 0;
1208 }
1209 };
1210
1211 template <typename To>
1213 static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *addr, const TConfiguration *config)
1214 {
1215 // Simple conversion from a 'From' on disk to a 'To' in memory
1216 UInt_t temp;
1217 buf >> temp;
1218
1219 if ((temp & kIsReferenced) != 0) {
1220 HandleReferencedTObject(buf,addr,config);
1221 }
1222
1223 *(To*)( ((char*)addr) + config->fOffset ) = (To)temp;
1224 return 0;
1225 }
1226 };
1227
1228 template <typename From, typename To>
1230 static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *addr, const TConfiguration *config)
1231 {
1232 // Simple conversion from a 'From' on disk to a 'To' in memory.
1234 From temp;
1235 buf.ReadWithFactor(&temp, conf->fFactor, conf->fXmin);
1236 *(To*)( ((char*)addr) + config->fOffset ) = (To)temp;
1237 return 0;
1238 }
1239 };
1240
1241 template <typename From, typename To>
1243 static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *addr, const TConfiguration *config)
1244 {
1245 // Simple conversion from a 'From' on disk to a 'To' in memory.
1246 TConfNoFactor *conf = (TConfNoFactor *)config;
1247 From temp;
1248 buf.ReadWithNbits(&temp, conf->fNbits);
1249 *(To*)( ((char*)addr) + config->fOffset ) = (To)temp;
1250 return 0;
1251 }
1252 };
1253
1255 // Configuration object for the PushDataCache case.
1256 public:
1258
1262
1263 void Print() const override
1264 {
1266 if (fOnfileObject)
1267 printf("StreamerInfoAction, class:%s, PushDataCache offset=%d\n",
1268 info->GetClass()->GetName(), fOffset);
1269 else
1270 printf("StreamerInfoAction, class:%s, PopDataCache offset=%d\n",
1271 info->GetClass()->GetName(), fOffset);
1272 }
1273 void PrintDebug(TBuffer &buffer, void *object) const override
1274 {
1275 if (gDebug > 1) {
1277 printf("StreamerInfoAction, class:%s, %sDataCache, bufpos=%d, arr=%p, offset=%d, onfileObject=%p\n",
1278 info->GetClass()->GetName(), fOnfileObject ? "Push" : "Pop", buffer.Length(), object, fOffset, fOnfileObject);
1279
1280 }
1281 }
1282 };
1283
1285 {
1287 auto onfileObject = config->fOnfileObject;
1288
1289 // onfileObject->SetSize(1);
1290 b.PushDataCache( onfileObject );
1291
1292 return 0;
1293 }
1294
1296 {
1298 auto onfileObject = config->fOnfileObject;
1299
1300 // onfileObject->SetSize(n);
1301 b.PushDataCache( onfileObject );
1302
1303 return 0;
1304 }
1305
1307 {
1309 auto onfileObject = config->fOnfileObject;
1310
1312 UInt_t n = proxy->Size();
1313
1314 onfileObject->SetSize(n);
1315 b.PushDataCache( onfileObject );
1316
1317 return 0;
1318 }
1319
1321 {
1322 b.PopDataCache();
1323 return 0;
1324 }
1325
1326 Int_t PopDataCacheVectorPtr(TBuffer &b, void *, const void *, const TConfiguration *)
1327 {
1328 b.PopDataCache();
1329 return 0;
1330 }
1331
1333 {
1334 b.PopDataCache();
1335 return 0;
1336 }
1337
1339 // Configuration object for the UseCache case.
1340 public:
1343
1346 void PrintDebug(TBuffer &b, void *addr) const override
1347 {
1348 if (gDebug > 1) {
1349 // Idea: We should print the name of the action function.
1352 fprintf(stdout,"StreamerInfoAction, class:%s, name=%s, fType[%d]=%d,"
1353 " %s, bufpos=%d, arr=%p, eoffset=%d, Redirect=%p\n",
1354 info->GetClass()->GetName(),aElement->GetName(),fElemId,fCompInfo->fType,
1355 aElement->ClassName(),b.Length(),addr, 0,b.PeekDataCache() ? b.PeekDataCache()->GetObjectAt(0) : 0);
1356 }
1357
1358 }
1361 {
1363 fAction.fConfiguration = copy->fAction.fConfiguration->Copy(); // since the previous allocation did a 'move' of fAction we need to fix it.
1364 return copy;
1365 }
1366 };
1367
1369 {
1371
1372 Int_t bufpos = b.Length();
1373 TVirtualArray *cached = b.PeekDataCache();
1374 if (cached==0) {
1375 TStreamerElement *aElement = conf->fCompInfo->fElem;
1377 Warning("ReadBuffer","Skipping %s::%s because the cache is missing.",info->GetName(),aElement->GetName());
1378 char *ptr = (char*)addr;
1379 info->ReadBufferSkip(b,&ptr,config->fCompInfo,config->fCompInfo->fType+TStreamerInfo::kSkip,aElement,1,0);
1380 } else {
1381 config->fAction(b, (*cached)[0]);
1382 }
1383 // Idea: Factor out this 'if' to a UseCacheRepeat function
1384 if (config->fNeedRepeat) {
1385 b.SetBufferOffset(bufpos);
1386 }
1387 return 0;
1388 }
1389
1391 {
1393 Int_t bufpos = b.Length();
1394
1395 TVirtualArray *cached = b.PeekDataCache();
1396 if (cached==0) {
1399 Warning("ReadBuffer","Skipping %s::%s because the cache is missing.",info->GetName(),aElement->GetName());
1400 char *ptr = (char*)start;
1401 UInt_t n = (((void**)end)-((void**)start));
1402 info->ReadBufferSkip(b,&ptr,config->fCompInfo,conf->fCompInfo->fType+TStreamerInfo::kSkip,aElement,n,0);
1403 } else {
1404 TVectorLoopConfig cached_config( nullptr, cached->fClass->Size(), /* read */ kTRUE );
1405 void *cached_start = (*cached)[0];
1406 void *cached_end = ((char*)cached_start) + cached->fSize * cached_config.fIncrement;
1408 }
1409 // Idea: Factor out this 'if' to a UseCacheRepeat function
1410 if (config->fNeedRepeat) {
1411 b.SetBufferOffset(bufpos);
1412 }
1413 return 0;
1414 }
1415
1417 {
1419
1420 Int_t bufpos = b.Length();
1421 TVirtualArray *cached = b.PeekDataCache();
1422 if (cached==0) {
1425 Warning("ReadBuffer","Skipping %s::%s because the cache is missing.",info->GetName(),aElement->GetName());
1426 char *ptr = (char*)start;
1427 UInt_t n = (((char*)end)-((char*)start))/((TVectorLoopConfig*)loopconf)->fIncrement;
1428 info->ReadBufferSkip(b,&ptr,config->fCompInfo,config->fCompInfo->fType+TStreamerInfo::kSkip,aElement,n,0);
1429 } else {
1430 TVectorLoopConfig cached_config( nullptr, cached->fClass->Size(), /* read */ kTRUE );
1431 void *cached_start = (*cached)[0];
1432 void *cached_end = ((char*)cached_start) + cached->fSize * cached_config.fIncrement;
1434 }
1435 // Idea: Factor out this 'if' to a UseCacheRepeat function
1436 if (config->fNeedRepeat) {
1437 b.SetBufferOffset(bufpos);
1438 }
1439 return 0;
1440 }
1441
1443 {
1445
1446 Int_t bufpos = b.Length();
1447 TVirtualArray *cached = b.PeekDataCache();
1448 if (cached==0) {
1451
1453 Warning("ReadBuffer","Skipping %s::%s because the cache is missing.",info->GetName(),aElement->GetName());
1454 UInt_t n = proxy->Size();
1455 info->ReadBufferSkip(b, *proxy,config->fCompInfo,config->fCompInfo->fType+TStreamerInfo::kSkip,aElement,n,0);
1456 } else {
1457 TVectorLoopConfig cached_config( nullptr, cached->fClass->Size(), /* read */ kTRUE );
1458 void *cached_start = (*cached)[0];
1459 void *cached_end = ((char*)cached_start) + cached->fSize * cached_config.fIncrement;
1461 }
1462 // Idea: Factor out this 'if' to a UseCacheRepeat function
1463 if (config->fNeedRepeat) {
1464 b.SetBufferOffset(bufpos);
1465 }
1466 return 0;
1467 }
1468
1469 // Support for collections.
1470
1471 Int_t ReadLoopInvalid(TBuffer &, void *, const void *, const TConfiguration *config)
1472 {
1473 Fatal("ApplySequence","The sequence of actions to read %s:%d member-wise was not initialized.",config->fInfo->GetName(),config->fInfo->GetClassVersion());
1474 return 0;
1475 }
1476
1477 Int_t WriteLoopInvalid(TBuffer &, void *, const void *, const TConfiguration *config)
1478 {
1479 Fatal("ApplySequence","The sequence of actions to write %s:%d member-wise was not initialized.",config->fInfo->GetName(),config->fInfo->GetClassVersion());
1480 return 0;
1481 }
1482
1484
1486 {
1487 if ( (proxy.GetProperties() & TVirtualCollectionProxy::kIsEmulated) ) {
1488 return kVectorLooper;
1489 } else if ( (proxy.GetCollectionType() == ROOT::kSTLvector)) {
1490 if (proxy.GetProperties() & TVirtualCollectionProxy::kCustomAlloc)
1491 return kGenericLooper;
1492 else
1493 return kVectorLooper;
1494 } else if (proxy.GetCollectionType() == ROOT::kSTLset || proxy.GetCollectionType() == ROOT::kSTLunorderedset
1495 || proxy.GetCollectionType() == ROOT::kSTLmultiset || proxy.GetCollectionType() == ROOT::kSTLunorderedmultiset
1496 || proxy.GetCollectionType() == ROOT::kSTLmap || proxy.GetCollectionType() == ROOT::kSTLmultimap
1497 || proxy.GetCollectionType() == ROOT::kSTLunorderedmap || proxy.GetCollectionType() == ROOT::kSTLunorderedmultimap
1498 || proxy.GetCollectionType() == ROOT::kSTLbitset) {
1499 return kAssociativeLooper;
1500 } else {
1501 return kGenericLooper;
1502 }
1503 }
1504
1506 {
1507 if (proxy)
1508 return SelectLooper(*proxy);
1509 else
1510 return kVectorPtrLooper;
1511 }
1512
1513
1514 template<typename Looper>
1516
1517 static std::unique_ptr<TStreamerInfoActions::TActionSequence>
1519 {
1521 std::unique_ptr<TStreamerInfoActions::TActionSequence> actions(
1523 return actions;
1524 }
1525
1526 static std::unique_ptr<TStreamerInfoActions::TActionSequence>
1528 {
1530 std::unique_ptr<TStreamerInfoActions::TActionSequence> actions(
1532 return actions;
1533 }
1534
1535 static inline Int_t SubSequenceAction(TBuffer &buf, void *start, const void *end, const TLoopConfiguration * /* loopconfig */, const TConfiguration *config)
1536 {
1537 auto conf = (TConfSubSequence*)config;
1538 auto actions = conf->fActions.get();
1539 // FIXME: need to update the signature of ApplySequence.
1540 buf.ApplySequence(*actions, start, const_cast<void*>(end));
1541 return 0;
1542 }
1543
1544 static inline Int_t ReadStreamerCase(TBuffer &buf, void *start, const void *end, const TLoopConfiguration * loopconfig, const TConfiguration *config)
1545 {
1546 UInt_t pos, count;
1547 /* Version_t v = */ buf.ReadVersion(&pos, &count, config->fInfo->IsA());
1548
1549 Looper::template LoopOverCollection< ReadViaExtStreamer >(buf, start, end, loopconfig, config);
1550
1551 buf.CheckByteCount(pos, count, config->fCompInfo->fElem->GetFullName());
1552 return 0;
1553 }
1554
1555 static inline Int_t WriteStreamerCase(TBuffer &buf, void *start, const void *end, const TLoopConfiguration * loopconfig, const TConfiguration *config)
1556 {
1557 UInt_t pos = buf.WriteVersion(config->fInfo->IsA(), kTRUE);
1558
1559 Looper::template LoopOverCollection< WriteViaExtStreamer >(buf, start, end, loopconfig, config);
1560
1561 buf.SetByteCount(pos, kTRUE);
1562 return 0;
1563 }
1564
1566 UInt_t ioffset = actionConfig->fOffset;
1567 // Get any private streamer which was set for the data member.
1568 TMemberStreamer* pstreamer = actionConfig->fCompInfo->fStreamer;
1569 Int_t* counter = (Int_t*) ((char *) addr /*entry pointer*/ + actionConfig->fCompInfo->fMethod /*counter offset*/);
1570 // And call the private streamer, passing it the buffer, the object, and the counter.
1571 (*pstreamer)(buf, (char *) addr /*entry pointer*/ + ioffset /*object offset*/, *counter);
1572 return 0;
1573 };
1574
1575 template<bool kIsTextT>
1576 static Int_t WriteStreamerLoopPoly(TBuffer &buf, void *addr, const TConfiguration *config) {
1577 // Get the class of the data member.
1578 TClass* cl = config->fCompInfo->fClass;
1579 UInt_t ioffset = config->fOffset;
1580 bool isPtrPtr = ((TConfStreamerLoop*)config)->fIsPtrPtr;
1581
1582 // Get the counter for the varying length array.
1583 Int_t vlen = *((Int_t*) ((char *) addr /*entry pointer*/ + config->fCompInfo->fMethod /*counter offset*/));
1584
1585 //b << vlen;
1586 if (vlen) {
1587 // Get a pointer to the array of pointers.
1588 char** pp = (char**) ((char *) addr /*entry pointer*/ + ioffset /*object offset*/);
1589 // Loop over each element of the array of pointers to varying-length arrays.
1590 for (Int_t ndx = 0; ndx < config->fCompInfo->fLength; ++ndx) {
1591 if (!pp[ndx]) {
1592 // -- We do not have a pointer to a varying-length array.
1593 // Error("WriteBufferAux", "The pointer to element %s::%s type %d (%s) is null\n", GetName(), aElement->GetFullName(), compinfo[i]->fType, aElement->GetTypeName());
1594 // ::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()));
1595 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());
1596 continue;
1597 }
1598 if (!isPtrPtr) {
1599 // -- We are a varying-length array of objects.
1600 // Write the entire array of objects to the buffer.
1601 // Note: Polymorphism is not allowed here.
1602 buf.WriteFastArray(pp[ndx], cl, vlen, nullptr);
1603 } else {
1604 // -- We are a varying-length array of pointers to objects.
1605 // Write the entire array of object pointers to the buffer.
1606 // Note: The object pointers are allowed to be polymorphic.
1607 buf.WriteFastArray((void **)pp[ndx], cl, vlen, kFALSE, nullptr);
1608 } // isPtrPtr
1609 } // ndx
1610 } else // vlen
1611 if (kIsTextT) {
1612 // special handling for the text-based streamers
1613 for (Int_t ndx = 0; ndx < config->fCompInfo->fLength; ++ndx)
1614 buf.WriteFastArray((void *)nullptr, cl, -1, nullptr);
1615 }
1616 return 0;
1617 }
1618
1619 static Int_t WriteStreamerLoopStatic(TBuffer &buf, void *addr, const TConfiguration *config) {
1620 // Get the class of the data member.
1621 TClass* cl = config->fCompInfo->fClass;
1622 UInt_t ioffset = config->fOffset;
1623 bool isPtrPtr = ((TConfStreamerLoop*)config)->fIsPtrPtr;
1624
1625 // Get the counter for the varying length array.
1626 Int_t vlen = *((Int_t*) ((char *) addr /*entry pointer*/ + config->fCompInfo->fMethod /*counter offset*/));
1627 //b << vlen;
1628 if (vlen) {
1629 // Get a pointer to the array of pointers.
1630 char** pp = (char**) ((char *) addr /*entry pointer*/ + ioffset /*object offset*/);
1631 // -- Older versions do *not* allow polymorphic pointers to objects.
1632 // Loop over each element of the array of pointers to varying-length arrays.
1633 for (Int_t ndx = 0; ndx < config->fCompInfo->fLength; ++ndx) {
1634 if (!pp[ndx]) {
1635 // -- We do not have a pointer to a varying-length array.
1636 //Error("WriteBufferAux", "The pointer to element %s::%s type %d (%s) is null\n", GetName(), aElement->GetFullName(), compinfo[i]->fType, aElement->GetTypeName());
1637 // ::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()));
1638 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());
1639 continue;
1640 }
1641 if (!isPtrPtr) {
1642 // -- We are a varying-length array of objects.
1643 // Loop over the elements of the varying length array.
1644 for (Int_t v = 0; v < vlen; ++v) {
1645 // Write the object to the buffer.
1646 cl->Streamer(pp[ndx] + (v * cl->Size()), buf);
1647 } // v
1648 }
1649 else {
1650 // -- We are a varying-length array of pointers to objects.
1651 // Loop over the elements of the varying length array.
1652 for (Int_t v = 0; v < vlen; ++v) {
1653 // Get a pointer to the object pointer.
1654 char** r = (char**) pp[ndx];
1655 // Write the object to the buffer.
1656 cl->Streamer(r[v], buf);
1657 } // v
1658 } // isPtrPtr
1659 } // ndx
1660 } // vlen
1661 return 0;
1662 }
1663
1664 template<bool kIsTextT, typename... Ts>
1666 static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *start, Ts... args, const TConfiguration *config)
1667 {
1668 if (!kIsTextT && config->fCompInfo->fStreamer) {
1669 // -- We have a private streamer.
1670 UInt_t pos = buf.WriteVersion(config->fInfo->IsA(), kTRUE);
1671
1672 // Loop over the entries in the clones array or the STL container.
1673 Looper::template LoopOverCollection< StreamerLoopExternal > (buf, start, args..., config);
1674
1675 buf.SetByteCount(pos, kTRUE);
1676 // We are done, next streamer element.
1677 return 0;
1678 }
1679
1680 // By default assume the file version is the newest.
1682
1683 if (!kIsTextT) {
1684 // At this point we do *not* have a private streamer.
1685 // Get the version of the file we are writing to.
1686 TFile* file = (TFile*) buf.GetParent();
1687 if (file) {
1688 fileVersion = file->GetVersion();
1689 }
1690 }
1691 // Write the class version to the buffer.
1692 UInt_t pos = buf.WriteVersion(config->fInfo->IsA(), kTRUE);
1693 if (fileVersion > 51508) {
1694 // -- Newer versions allow polymorphic pointers to objects.
1695 // Loop over the entries in the clones array or the STL container.
1696 Looper::template LoopOverCollection< WriteStreamerLoopPoly<kIsTextT> > (buf, start, args..., config);
1697 }
1698 else {
1699 // -- Older versions do *not* allow polymorphic pointers to objects.
1700 // Loop over the entries in the clones array or the STL container.
1701 Looper::template LoopOverCollection< ReadStreamerLoopStatic > (buf, start, args..., config);
1702 } // fileVersion
1703 // Backpatch the byte count into the buffer.
1704 buf.SetByteCount(pos, kTRUE);
1705
1706 return 0;
1707 }
1708 };
1709
1710 template<bool kIsTextT>
1711 static Int_t ReadStreamerLoopPoly(TBuffer &buf, void *addr, const TConfiguration *config) {
1712 // Get the class of the data member.
1713 TClass* cl = config->fCompInfo->fClass;
1714 UInt_t ioffset = config->fOffset;
1715 // Which are we, an array of objects or an array of pointers to objects?
1716 bool isPtrPtr = ((TConfStreamerLoop*)config)->fIsPtrPtr;
1717
1718 // Get the counter for the varying length array.
1719 Int_t vlen = *((Int_t *)((char *)addr /*entry pointer*/ +
1720 config->fCompInfo->fMethod /*counter offset*/));
1721 // Int_t realLen;
1722 // b >> realLen;
1723 // if (realLen != vlen) {
1724 // fprintf(stderr, "read vlen: %d realLen: %s\n", vlen, realLen);
1725 //}
1726 // Get a pointer to the array of pointers.
1727 char **pp = (char **)((char *)addr /*entry pointer*/ + ioffset /*object offset*/);
1728 // Loop over each element of the array of pointers to varying-length arrays.
1729 // if (!pp) {
1730 // continue;
1731 // }
1732
1733 if (pp) // SL: place it here instead of continue, which is related to for(k) loop
1734 for (Int_t ndx = 0; ndx < config->fCompInfo->fLength; ++ndx) {
1735 // if (!pp[ndx]) {
1736 // -- We do not have a pointer to a varying-length array.
1737 // Error("ReadBuffer", "The pointer to element %s::%s type %d (%s) is null\n", thisVar->GetName(),
1738 // aElement->GetFullName(), compinfo[i]->fType, aElement->GetTypeName());
1739 // continue;
1740 //}
1741 // Delete any memory at pp[ndx].
1742 if (!isPtrPtr) {
1743 cl->DeleteArray(pp[ndx]);
1744 pp[ndx] = 0;
1745 } else {
1746 // Using vlen is wrong here because it has already
1747 // been overwritten with the value needed to read
1748 // the current record. Fixing this will require
1749 // doing a pass over the object at the beginning
1750 // of the I/O and releasing all the buffer memory
1751 // for varying length arrays before we overwrite
1752 // the counter values.
1753 //
1754 // For now we will just leak memory, just as we
1755 // have always done in the past. Fix this.
1756 //
1757 // char** r = (char**) pp[ndx];
1758 // if (r) {
1759 // for (Int_t v = 0; v < vlen; ++v) {
1760 // cl->Destructor(r[v]);
1761 // r[v] = 0;
1762 // }
1763 //}
1764 delete[] pp[ndx];
1765 pp[ndx] = 0;
1766 }
1767 if (!vlen) {
1768 if (kIsTextT) {
1769 // special handling for the text-based streamers - keep calling to shift array index
1770 buf.ReadFastArray((void *)nullptr, cl, -1, nullptr);
1771 }
1772 continue;
1773 }
1774 // Note: We now have pp[ndx] is null.
1775 // Allocate memory to read into.
1776 if (!isPtrPtr) {
1777 // -- We are a varying-length array of objects.
1778 // Note: Polymorphism is not allowed here.
1779 // Allocate a new array of objects to read into.
1780 pp[ndx] = (char *)cl->NewArray(vlen);
1781 if (!pp[ndx]) {
1782 Error("ReadBuffer", "Memory allocation failed!\n");
1783 continue;
1784 }
1785 } else {
1786 // -- We are a varying-length array of pointers to objects.
1787 // Note: The object pointers are allowed to be polymorphic.
1788 // Allocate a new array of pointers to objects to read into.
1789 pp[ndx] = (char *)new char *[vlen];
1790 if (!pp[ndx]) {
1791 Error("ReadBuffer", "Memory allocation failed!\n");
1792 continue;
1793 }
1794 // And set each pointer to null.
1795 memset(pp[ndx], 0, vlen * sizeof(char *)); // This is the right size we really have a char**: pp[ndx]
1796 // = (char*) new char*[vlen];
1797 }
1798 if (!isPtrPtr) {
1799 // -- We are a varying-length array of objects.
1800 buf.ReadFastArray(pp[ndx], cl, vlen, nullptr);
1801 } else {
1802 // -- We are a varying-length array of object pointers.
1803 buf.ReadFastArray((void **)pp[ndx], cl, vlen, kFALSE, nullptr);
1804 } // isPtrPtr
1805 } // ndx
1806 return 0;
1807 }; // StreamerLoopPoly
1808
1809 static Int_t ReadStreamerLoopStatic(TBuffer &buf, void *addr, const TConfiguration *config) {
1810 // Get the class of the data member.
1811 TClass* cl = config->fCompInfo->fClass;
1812 UInt_t ioffset = config->fOffset;
1813 // Which are we, an array of objects or an array of pointers to objects?
1814 bool isPtrPtr = ((TConfStreamerLoop*)config)->fIsPtrPtr;
1815
1816 // Get the counter for the varying length array.
1817 Int_t vlen = *((Int_t *)((char *)addr /*entry pointer*/ +
1818 config->fCompInfo->fMethod /*counter offset*/));
1819 // Int_t realLen;
1820 // b >> realLen;
1821 // if (realLen != vlen) {
1822 // fprintf(stderr, "read vlen: %d realLen: %s\n", vlen, realLen);
1823 //}
1824 // Get a pointer to the array of pointers.
1825 char **pp = (char **)((char *)addr /*entry pointer*/ + ioffset /*object offset*/);
1826 // if (!pp) {
1827 // continue;
1828 //}
1829
1830 if (pp) // SL: place it here instead of continue, which is related to for(k) loop
1831
1832 // Loop over each element of the array of pointers to varying-length arrays.
1833 for (Int_t ndx = 0; ndx < config->fCompInfo->fLength; ++ndx) {
1834 // if (!pp[ndx]) {
1835 // -- We do not have a pointer to a varying-length array.
1836 // Error("ReadBuffer", "The pointer to element %s::%s type %d (%s) is null\n", thisVar->GetName(),
1837 // aElement->GetFullName(), compinfo[i]->fType, aElement->GetTypeName());
1838 // continue;
1839 //}
1840 // Delete any memory at pp[ndx].
1841 if (!isPtrPtr) {
1842 cl->DeleteArray(pp[ndx]);
1843 pp[ndx] = 0;
1844 } else {
1845 // Using vlen is wrong here because it has already
1846 // been overwritten with the value needed to read
1847 // the current record. Fixing this will require
1848 // doing a pass over the object at the beginning
1849 // of the I/O and releasing all the buffer memory
1850 // for varying length arrays before we overwrite
1851 // the counter values.
1852 //
1853 // For now we will just leak memory, just as we
1854 // have always done in the past. Fix this.
1855 //
1856 // char** r = (char**) pp[ndx];
1857 // if (r) {
1858 // for (Int_t v = 0; v < vlen; ++v) {
1859 // cl->Destructor(r[v]);
1860 // r[v] = 0;
1861 // }
1862 //}
1863 delete[] pp[ndx];
1864 pp[ndx] = 0;
1865 }
1866 if (!vlen) {
1867 continue;
1868 }
1869 // Note: We now have pp[ndx] is null.
1870 // Allocate memory to read into.
1871 if (!isPtrPtr) {
1872 // -- We are a varying-length array of objects.
1873 // Note: Polymorphism is not allowed here.
1874 // Allocate a new array of objects to read into.
1875 pp[ndx] = (char *)cl->NewArray(vlen);
1876 if (!pp[ndx]) {
1877 Error("ReadBuffer", "Memory allocation failed!\n");
1878 continue;
1879 }
1880 } else {
1881 // -- We are a varying-length array of pointers to objects.
1882 // Note: The object pointers are allowed to be polymorphic.
1883 // Allocate a new array of pointers to objects to read into.
1884 pp[ndx] = (char *)new char *[vlen];
1885 if (!pp[ndx]) {
1886 Error("ReadBuffer", "Memory allocation failed!\n");
1887 continue;
1888 }
1889 // And set each pointer to null.
1890 memset(pp[ndx], 0, vlen * sizeof(char *)); // This is the right size we really have a char**: pp[ndx]
1891 // = (char*) new char*[vlen];
1892 }
1893 if (!isPtrPtr) {
1894 // -- We are a varying-length array of objects.
1895 // Loop over the elements of the varying length array.
1896 for (Int_t v = 0; v < vlen; ++v) {
1897 // Read the object from the buffer.
1898 cl->Streamer(pp[ndx] + (v * cl->Size()), buf);
1899 } // v
1900 } else {
1901 // -- We are a varying-length array of object pointers.
1902 // Get a pointer to the object pointer array.
1903 char **r = (char **)pp[ndx];
1904 // Loop over the elements of the varying length array.
1905 for (Int_t v = 0; v < vlen; ++v) {
1906 // Allocate an object to read into.
1907 r[v] = (char *)cl->New();
1908 if (!r[v]) {
1909 // Do not print a second error message here.
1910 // Error("ReadBuffer", "Memory allocation failed!\n");
1911 continue;
1912 }
1913 // Read the object from the buffer.
1914 cl->Streamer(r[v], buf);
1915 } // v
1916 } // isPtrPtr
1917 } // ndx
1918 return 0;
1919 }; // action
1920
1921 template<bool kIsTextT, typename... Ts>
1923 static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *start, Ts... args, const TConfiguration *config)
1924 {
1925 // Check for a private streamer.
1926 if (!kIsTextT && config->fCompInfo->fStreamer) {
1927 // -- We have a private streamer.
1928 // Read the class version and byte count from the buffer.
1929 UInt_t pos = 0;
1930 UInt_t count = 0;
1931 buf.ReadVersion(&pos, &count, config->fInfo->IsA());
1932
1933 // Loop over the entries in the clones array or the STL container.
1934 Looper::template LoopOverCollection< StreamerLoopExternal > (buf, start, args..., config);
1935
1936 buf.CheckByteCount(pos, count, config->fCompInfo->fElem->GetFullName());
1937 // We are done, next streamer element.
1938 return 0;
1939 }
1940
1941 // By default assume the file version is the newest.
1943 if (!kIsTextT) {
1944 // At this point we do *not* have a private streamer.
1945 // Get the version of the file we are reading from.
1946 TFile* file = (TFile*) buf.GetParent();
1947 if (file) {
1948 fileVersion = file->GetVersion();
1949 }
1950 }
1951 // Read the class version and byte count from the buffer.
1952 UInt_t pos = 0;
1953 UInt_t count = 0;
1954 buf.ReadVersion(&pos, &count, config->fInfo->IsA());
1955 if (fileVersion > 51508) {
1956 // -- Newer versions allow polymorphic pointers.
1957
1958 // Loop over the entries in the clones array or the STL container.
1959 Looper::template LoopOverCollection< ReadStreamerLoopPoly<kIsTextT> > (buf, start, args..., config);
1960 } else {
1961 // -- Older versions do *not* allow polymorphic pointers.
1962
1963 // Loop over the entries in the clones array or the STL container.
1964 Looper::template LoopOverCollection< ReadStreamerLoopStatic > (buf, start, args..., config);
1965 } // fileVersion
1966 buf.CheckByteCount(pos, count, config->fCompInfo->fElem->GetFullName());
1967 return 0;
1968 }
1969 };
1970
1971 };
1972
1973 // The Scalar 'looper' only process one element.
1974 struct ScalarLooper : public CollectionLooper<ScalarLooper>
1975 {
1976 using LoopAction_t = Int_t (*)(TBuffer &, void*, const TConfiguration*);
1977
1978 template <Int_t (*iter_action)(TBuffer&,void *,const TConfiguration*)>
1979 static INLINE_TEMPLATE_ARGS Int_t LoopOverCollection(TBuffer &buf, void *start, const TConfiguration *config)
1980 {
1981 iter_action(buf, start, config);
1982 return 0;
1983 }
1984 };
1985
1986 struct VectorLooper : public CollectionLooper<VectorLooper>
1987 {
1988 using LoopAction_t = Int_t (*)(TBuffer &, void*, const void *end, const TLoopConfiguration *loopconfig, const TConfiguration*);
1989
1990 template <bool kIsText>
1992 template <bool kIsText>
1994
1995 template <Int_t (*iter_action)(TBuffer&,void *,const TConfiguration*)>
1996 static INLINE_TEMPLATE_ARGS Int_t LoopOverCollection(TBuffer &buf, void *start, const void *end, const TLoopConfiguration *loopconfig, const TConfiguration *config)
1997 {
1998 const Int_t incr = ((TVectorLoopConfig*)loopconfig)->fIncrement;
1999 //Idea: can we factor out the addition of fOffset
2000 // iter = (char*)iter + config->fOffset;
2001 for(void *iter = start; iter != end; iter = (char*)iter + incr ) {
2002 iter_action(buf, iter, config);
2003 }
2004 return 0;
2005 }
2006
2007 template <typename T>
2008 static INLINE_TEMPLATE_ARGS Int_t ReadBasicType(TBuffer &buf, void *iter, const void *end, const TLoopConfiguration *loopconfig, const TConfiguration *config)
2009 {
2010 const Int_t incr = ((TVectorLoopConfig*)loopconfig)->fIncrement;
2011 iter = (char*)iter + config->fOffset;
2012 end = (char*)end + config->fOffset;
2013 for(; iter != end; iter = (char*)iter + incr ) {
2014 T *x = (T*) ((char*) iter);
2015 buf >> *x;
2016 }
2017 return 0;
2018 }
2019
2020 template <typename From, typename To>
2022 static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *iter, const void *end, const TLoopConfiguration *loopconfig, const TConfiguration *config)
2023 {
2024 // Simple conversion from a 'From' on disk to a 'To' in memory.
2025 From temp;
2026 const Int_t incr = ((TVectorLoopConfig*)loopconfig)->fIncrement;
2027 iter = (char*)iter + config->fOffset;
2028 end = (char*)end + config->fOffset;
2029 for(; iter != end; iter = (char*)iter + incr ) {
2030 buf >> temp;
2031 *(To*)( ((char*)iter) ) = (To)temp;
2032 }
2033 return 0;
2034 }
2035 };
2036
2037 template <typename To>
2039 static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *iter, const void *end, const TLoopConfiguration *loopconfig, const TConfiguration *config)
2040 {
2041 // Simple conversion from a 'From' on disk to a 'To' in memory.
2042 UInt_t temp;
2043 const Int_t incr = ((TVectorLoopConfig*)loopconfig)->fIncrement;
2044 iter = (char*)iter + config->fOffset;
2045 end = (char*)end + config->fOffset;
2046 for(; iter != end; iter = (char*)iter + incr ) {
2047 buf >> temp;
2048
2049 if ((temp & kIsReferenced) != 0) {
2050 HandleReferencedTObject(buf, (char*)iter - config->fOffset, config);
2051 }
2052
2053 *(To*)( ((char*)iter) ) = (To)temp;
2054 }
2055 return 0;
2056 }
2057 };
2058
2059 template <typename From, typename To>
2061 static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *iter, const void *end, const TLoopConfiguration *loopconfig, const TConfiguration *config)
2062 {
2063 // Simple conversion from a 'From' on disk to a 'To' in memory.
2065 From temp;
2066 const Int_t incr = ((TVectorLoopConfig*)loopconfig)->fIncrement;
2067 iter = (char*)iter + config->fOffset;
2068 end = (char*)end + config->fOffset;
2069 for(; iter != end; iter = (char*)iter + incr ) {
2070 buf.ReadWithFactor(&temp, conf->fFactor, conf->fXmin);
2071 *(To*)( ((char*)iter) ) = (To)temp;
2072 }
2073 return 0;
2074 }
2075 };
2076
2077 template <typename From, typename To>
2079 static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *iter, const void *end, const TLoopConfiguration *loopconfig, const TConfiguration *config)
2080 {
2081 // Simple conversion from a 'From' on disk to a 'To' in memory.
2082 TConfNoFactor *conf = (TConfNoFactor *)config;
2083 From temp;
2084 const Int_t incr = ((TVectorLoopConfig*)loopconfig)->fIncrement;
2085 iter = (char*)iter + config->fOffset;
2086 end = (char*)end + config->fOffset;
2087 for(; iter != end; iter = (char*)iter + incr ) {
2088 buf.ReadWithNbits(&temp, conf->fNbits);
2089 *(To*)( ((char*)iter) ) = (To)temp;
2090 }
2091 return 0;
2092 }
2093 };
2094
2095 template <typename T>
2096 static INLINE_TEMPLATE_ARGS Int_t WriteBasicType(TBuffer &buf, void *iter, const void *end, const TLoopConfiguration *loopconfig, const TConfiguration *config)
2097 {
2098 const Int_t incr = ((TVectorLoopConfig*)loopconfig)->fIncrement;
2099 iter = (char*)iter + config->fOffset;
2100 end = (char*)end + config->fOffset;
2101 for(; iter != end; iter = (char*)iter + incr ) {
2102 T *x = (T*) ((char*) iter);
2103 buf << *x;
2104 }
2105 return 0;
2106 }
2107
2108 template <typename Onfile, typename Memory>
2110 static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *iter, const void *end, const TLoopConfiguration *loopconfig, const TConfiguration *config)
2111 {
2112 const Int_t incr = ((TVectorLoopConfig*)loopconfig)->fIncrement;
2113 iter = (char*)iter + config->fOffset;
2114 end = (char*)end + config->fOffset;
2115 for(; iter != end; iter = (char*)iter + incr ) {
2116 // Simple conversion from a 'From' on disk to a 'To' in memory.
2117 Onfile temp = (Onfile)(*(Memory*)((char*) iter));
2118 buf << temp;
2119 }
2120 return 0;
2121 }
2122 };
2123
2124 template <typename Onfile, typename Memory>
2126 static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *iter, const void *end, const TLoopConfiguration *loopconfig, const TConfiguration *config)
2127 {
2128 const TStreamerElement *elem = config->fCompInfo->fElem;
2129 const Int_t incr = ((TVectorLoopConfig*)loopconfig)->fIncrement;
2130 iter = (char*)iter + config->fOffset;
2131 end = (char*)end + config->fOffset;
2132 for(; iter != end; iter = (char*)iter + incr ) {
2133 // Simple conversion from a 'From' on disk to a 'To' in memory.
2134 Onfile temp = (Onfile)(*(Memory*)((char*) iter));
2135 WriteCompressed(buf, &temp, elem);
2136 }
2137 return 0;
2138 }
2139 };
2140
2141 template <typename Onfile, typename Memory>
2143 static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *iter, const void *end, const TLoopConfiguration *loopconfig, const TConfiguration *config)
2144 {
2145 const TStreamerElement *elem = config->fCompInfo->fElem;
2146 const Int_t incr = ((TVectorLoopConfig*)loopconfig)->fIncrement;
2147 iter = (char*)iter + config->fOffset;
2148 end = (char*)end + config->fOffset;
2149 for(; iter != end; iter = (char*)iter + incr ) {
2150 // Simple conversion from a 'From' on disk to a 'To' in memory.
2151 Onfile temp = (Onfile)(*(Memory*)((char*) iter));
2152 WriteCompressed(buf, &temp, elem);
2153 }
2154 return 0;
2155 }
2156 };
2157
2158 static INLINE_TEMPLATE_ARGS Int_t ReadBase(TBuffer &buf, void *start, const void *end, const TLoopConfiguration * loopconfig, const TConfiguration *config)
2159 {
2160 // Well the implementation is non trivial since we do not have a proxy for the container of _only_ the base class. For now
2161 // punt.
2162
2163 UInt_t incr = ((TVectorLoopConfig*)loopconfig)->fIncrement;
2164 UInt_t n = (((char*)end)-((char*)start))/incr;
2165 char **arrptr = new char*[n];
2166 UInt_t i = 0;
2167 for(void *iter = start; iter != end; iter = (char*)iter + incr, ++i ) {
2168 arrptr[i] = (char*)iter;
2169 }
2170 ((TStreamerInfo*)config->fInfo)->ReadBuffer(buf, arrptr, &(config->fCompInfo), /*first*/ 0, /*last*/ 1, /*narr*/ n, config->fOffset, 1|2 );
2171 delete [] arrptr;
2172 return 0;
2173 }
2174
2175 static INLINE_TEMPLATE_ARGS Int_t WriteBase(TBuffer &buf, void *start, const void *end, const TLoopConfiguration * loopconfig, const TConfiguration *config)
2176 {
2177 // Well the implementation is non trivial since we do not have a proxy for the container of _only_ the base class. For now
2178 // punt.
2179
2180 UInt_t incr = ((TVectorLoopConfig*)loopconfig)->fIncrement;
2181 UInt_t n = (((char*)end)-((char*)start))/incr;
2182 char **arrptr = new char*[n];
2183 UInt_t i = 0;
2184 for(void *iter = start; iter != end; iter = (char*)iter + incr, ++i ) {
2185 arrptr[i] = (char*)iter;
2186 }
2187 ((TStreamerInfo*)config->fInfo)->WriteBufferAux(buf, arrptr, &(config->fCompInfo), /*first*/ 0, /*last*/ 1, /*narr*/ n, config->fOffset, 1|2 );
2188 delete [] arrptr;
2189 return 0;
2190 }
2191
2192 static INLINE_TEMPLATE_ARGS Int_t GenericRead(TBuffer &buf, void *start, const void *end, const TLoopConfiguration * loopconfig, const TConfiguration *config)
2193 {
2194 // Well the implementation is non trivial. For now punt.
2195
2196 UInt_t incr = ((TVectorLoopConfig*)loopconfig)->fIncrement;
2197 UInt_t n = (((char*)end)-((char*)start))/incr;
2198 char **arrptr = new char*[n];
2199 UInt_t i = 0;
2200 for(void *iter = start; iter != end; iter = (char*)iter + incr, ++i ) {
2201 arrptr[i] = (char*)iter;
2202 }
2203 ((TStreamerInfo*)config->fInfo)->ReadBuffer(buf, arrptr, &(config->fCompInfo), /*first*/ 0, /*last*/ 1, /*narr*/ n, config->fOffset, 1|2 );
2204 delete [] arrptr;
2205 return 0;
2206 }
2207
2208 static INLINE_TEMPLATE_ARGS Int_t GenericWrite(TBuffer &buf, void *start, const void *end, const TLoopConfiguration * loopconfig, const TConfiguration *config)
2209 {
2210 // Well the implementation is non trivial. For now punt.
2211
2212 UInt_t incr = ((TVectorLoopConfig*)loopconfig)->fIncrement;
2213 UInt_t n = (((char*)end)-((char*)start))/incr;
2214 char **arrptr = new char*[n];
2215 UInt_t i = 0;
2216 for(void *iter = start; iter != end; iter = (char*)iter + incr, ++i ) {
2217 arrptr[i] = (char*)iter;
2218 }
2219 ((TStreamerInfo*)config->fInfo)->WriteBufferAux(buf, arrptr, &(config->fCompInfo), /*first*/ 0, /*last*/ 1, n, config->fOffset, 1|2 );
2220 delete [] arrptr;
2221 return 0;
2222 }
2223
2224 template <typename T>
2226 {
2227 // Collection of numbers. Memberwise or not, it is all the same.
2228
2229 TConfigSTL *config = (TConfigSTL*)conf;
2230 UInt_t start, count;
2231 /* Version_t vers = */ buf.ReadVersion(&start, &count, config->fOldClass);
2232
2233 std::vector<T> *const vec = (std::vector<T>*)(((char*)addr)+config->fOffset);
2234 Int_t nvalues;
2235 buf.ReadInt(nvalues);
2236 vec->resize(nvalues);
2237
2238#ifdef R__VISUAL_CPLUSPLUS
2239 if (nvalues <= 0) {
2240 buf.CheckByteCount(start,count,config->fTypeName);
2241 return 0;
2242 }
2243#endif
2244 T *begin = vec->data();
2245 buf.ReadFastArray(begin, nvalues);
2246
2247 buf.CheckByteCount(start,count,config->fTypeName);
2248 return 0;
2249 }
2250
2251 template <typename T>
2253 {
2254 // Collection of numbers. Memberwise or not, it is all the same.
2255
2256 TConfigSTL *config = (TConfigSTL*)conf;
2257 UInt_t start = buf.WriteVersion(config->fInfo->IsA(), kTRUE);
2258
2259 std::vector<T> *const vec = (std::vector<T>*)(((char*)addr)+config->fOffset);
2260 Int_t nvalues = vec->size();
2261 buf.WriteInt(nvalues);
2262
2263 T *begin = vec->data();
2264 buf.WriteFastArray(begin, nvalues);
2265
2266 buf.SetByteCount(start);
2267 return 0;
2268 }
2269
2271 {
2272 // Collection of numbers. Memberwise or not, it is all the same.
2273
2274 TConfigSTL *config = (TConfigSTL*)conf;
2275 UInt_t start, count;
2276 /* Version_t vers = */ buf.ReadVersion(&start, &count, config->fOldClass);
2277
2278 std::vector<float> *const vec = (std::vector<float>*)(((char*)addr)+config->fOffset);
2279 Int_t nvalues;
2280 buf.ReadInt(nvalues);
2281 vec->resize(nvalues);
2282
2283#ifdef R__VISUAL_CPLUSPLUS
2284 if (nvalues <= 0) {
2285 buf.CheckByteCount(start,count,config->fTypeName);
2286 return 0;
2287 }
2288#endif
2289 float *begin = vec->data();
2290 buf.ReadFastArrayFloat16(begin, nvalues);
2291
2292 buf.CheckByteCount(start,count,config->fTypeName);
2293 return 0;
2294 }
2295
2297 {
2298 // Collection of numbers. Memberwise or not, it is all the same.
2299
2300 TConfigSTL *config = (TConfigSTL*)conf;
2301 UInt_t start = buf.WriteVersion(config->fInfo->IsA(), kTRUE);
2302
2303 std::vector<float> *const vec = (std::vector<float>*)(((char*)addr)+config->fOffset);
2304 Int_t nvalues = vec->size();
2305 buf.WriteInt(nvalues);
2306
2307 float *begin = vec->data();
2308 buf.WriteFastArrayFloat16(begin, nvalues);
2309
2310 buf.SetByteCount(start);
2311 return 0;
2312 }
2313
2315 {
2316 // Collection of numbers. Memberwise or not, it is all the same.
2317
2318 TConfigSTL *config = (TConfigSTL*)conf;
2319 UInt_t start, count;
2320 /* Version_t vers = */ buf.ReadVersion(&start, &count, config->fOldClass);
2321
2322 std::vector<double> *const vec = (std::vector<double>*)(((char*)addr)+config->fOffset);
2323 Int_t nvalues;
2324 buf.ReadInt(nvalues);
2325 vec->resize(nvalues);
2326
2327#ifdef R__VISUAL_CPLUSPLUS
2328 if (nvalues <= 0) {
2329 buf.CheckByteCount(start,count,config->fTypeName);
2330 return 0;
2331 }
2332#endif
2333 double *begin = vec->data();
2334 buf.ReadFastArrayDouble32(begin, nvalues);
2335
2336 buf.CheckByteCount(start,count,config->fTypeName);
2337 return 0;
2338 }
2339
2341 {
2342 // Collection of numbers. Memberwise or not, it is all the same.
2343
2344 TConfigSTL *config = (TConfigSTL*)conf;
2345 UInt_t start = buf.WriteVersion(config->fInfo->IsA(), kTRUE);
2346
2347 std::vector<double> *const vec = (std::vector<double>*)(((char*)addr)+config->fOffset);
2348 Int_t nvalues = vec->size();
2349 buf.WriteInt(nvalues);
2350
2351 double *begin = vec->data();
2352 buf.WriteFastArrayDouble32(begin, nvalues);
2353
2354 buf.SetByteCount(start);
2355 return 0;
2356 }
2357
2358 template <typename From, typename To>
2361 {
2362 // Collection of numbers. Memberwise or not, it is all the same.
2363
2364 TConfigSTL *config = (TConfigSTL*)conf;
2365 UInt_t start, count;
2366 /* Version_t vers = */ buf.ReadVersion(&start, &count, config->fOldClass);
2367
2368 std::vector<To> *const vec = (std::vector<To>*)(((char*)addr)+config->fOffset);
2369 Int_t nvalues;
2370 buf.ReadInt(nvalues);
2371 vec->resize(nvalues);
2372
2373 From *temp = new From[nvalues];
2374 buf.ReadFastArray(temp, nvalues);
2375 for(Int_t ind = 0; ind < nvalues; ++ind) {
2376 (*vec)[ind] = (To)temp[ind];
2377 }
2378 delete [] temp;
2379
2380 buf.CheckByteCount(start,count,config->fTypeName);
2381 return 0;
2382 }
2383 };
2384
2385 template <typename From, typename To>
2388 {
2389 // Collection of numbers. Memberwise or not, it is all the same.
2390
2391 TConfigSTL *config = (TConfigSTL*)conf;
2392 UInt_t start, count;
2393 /* Version_t vers = */ buf.ReadVersion(&start, &count, config->fOldClass);
2394
2395 std::vector<To> *const vec = (std::vector<To>*)(((char*)addr)+config->fOffset);
2396 Int_t nvalues;
2397 buf.ReadInt(nvalues);
2398 vec->resize(nvalues);
2399
2400 From *temp = new From[nvalues];
2401 buf.ReadFastArrayWithNbits(temp, nvalues, 0);
2402 for(Int_t ind = 0; ind < nvalues; ++ind) {
2403 (*vec)[ind] = (To)temp[ind];
2404 }
2405 delete [] temp;
2406
2407 buf.CheckByteCount(start,count,config->fTypeName);
2408 return 0;
2409 }
2410 };
2411
2412 template <typename To>
2414 {
2415 // Collection of numbers. Memberwise or not, it is all the same.
2416
2417 TConfigSTL *config = (TConfigSTL*)conf;
2418 UInt_t start, count;
2419 /* Version_t vers = */ buf.ReadVersion(&start, &count, config->fOldClass);
2420
2421 std::vector<To> *const vec = (std::vector<To>*)(((char*)addr)+config->fOffset);
2422 Int_t nvalues;
2423 buf.ReadInt(nvalues);
2424 vec->resize(nvalues);
2425
2426 Double32_t *temp = new Double32_t[nvalues];
2427 buf.ReadFastArrayDouble32(temp, nvalues);
2428 for(Int_t ind = 0; ind < nvalues; ++ind) {
2429 (*vec)[ind] = (To)temp[ind];
2430 }
2431 delete [] temp;
2432
2433 buf.CheckByteCount(start,count,config->fTypeName);
2434 return 0;
2435 }
2436
2437 template <typename Memory, typename Onfile>
2440 {
2441 // Collection of numbers. Memberwise or not, it is all the same.
2442
2443 TConfigSTL *config = (TConfigSTL*)conf;
2444 UInt_t start = buf.WriteVersion( config->fInfo->IsA(), kTRUE );
2445
2446 std::vector<Memory> *const vec = (std::vector<Memory>*)(((char*)addr)+config->fOffset);
2447 Int_t nvalues = vec->size();
2448 buf.WriteInt(nvalues);
2449
2450 // We have to call WriteFastArray for proper JSON writing
2451 // So we need to convert before hand :(
2452 Onfile *temp = new Onfile[nvalues];
2453 for(Int_t ind = 0; ind < nvalues; ++ind) {
2454 temp[ind] = (Onfile)((*vec)[ind]);
2455 }
2456 buf.WriteFastArray(temp, nvalues);
2457 delete [] temp;
2458
2459 buf.SetByteCount(start, kTRUE);
2460 return 0;
2461 }
2462 };
2463 };
2464
2465 struct VectorPtrLooper : public CollectionLooper<VectorPtrLooper> {
2466 // Can not inherit/use CollectionLooper<VectorPtrLooper>, because this looper's
2467 // function do not take a `TLoopConfiguration`.
2468
2469 using LoopAction_t = Int_t (*)(TBuffer &, void *start, const void *end, const TConfiguration*);
2470
2471 template <bool kIsText>
2473 template <bool kIsText>
2475
2476 static std::unique_ptr<TStreamerInfoActions::TActionSequence>
2478 {
2479 using unique_ptr = std::unique_ptr<TStreamerInfoActions::TActionSequence>;
2480 return unique_ptr(info.GetReadMemberWiseActions(kTRUE)->CreateCopy());
2481 }
2482
2483 static std::unique_ptr<TStreamerInfoActions::TActionSequence>
2485 {
2486 using unique_ptr = std::unique_ptr<TStreamerInfoActions::TActionSequence>;
2487 return unique_ptr(info.GetWriteMemberWiseActions(kTRUE)->CreateCopy());
2488 }
2489
2490 template <Int_t (*action)(TBuffer&,void *,const TConfiguration*)>
2491 static INLINE_TEMPLATE_ARGS Int_t LoopOverCollection(TBuffer &buf, void *start, const void *end, const TConfiguration *config)
2492 {
2493 for(void *iter = start; iter != end; iter = (char*)iter + sizeof(void*) ) {
2494 action(buf, *(void**)iter, config);
2495 }
2496 return 0;
2497 }
2498
2499 static inline Int_t SubSequenceAction(TBuffer &buf, void *start, const void *end, const TConfiguration *config)
2500 {
2501 auto conf = (TConfSubSequence*)config;
2502 auto actions = conf->fActions.get();
2503 // FIXME: need to update the signature of ApplySequence.
2504 buf.ApplySequenceVecPtr(*actions, start, const_cast<void*>(end));
2505 return 0;
2506 }
2507
2508 template <typename T>
2509 static INLINE_TEMPLATE_ARGS Int_t ReadBasicType(TBuffer &buf, void *iter, const void *end, const TConfiguration *config)
2510 {
2511 const Int_t offset = config->fOffset;
2512
2513 for(; iter != end; iter = (char*)iter + sizeof(void*) ) {
2514 T *x = (T*)( ((char*) (*(void**)iter) ) + offset );
2515 buf >> *x;
2516 }
2517 return 0;
2518 }
2519
2520 template <typename From, typename To>
2522 static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *iter, const void *end, const TConfiguration *config)
2523 {
2524 // Simple conversion from a 'From' on disk to a 'To' in memory.
2525 From temp;
2526 const Int_t offset = config->fOffset;
2527 for(; iter != end; iter = (char*)iter + sizeof(void*) ) {
2528 buf >> temp;
2529 To *x = (To*)( ((char*) (*(void**)iter) ) + offset );
2530 *x = (To)temp;
2531 }
2532 return 0;
2533 }
2534 };
2535
2536 template <typename To>
2538 static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *iter, const void *end, const TConfiguration *config)
2539 {
2540 // Simple conversion from a 'From' on disk to a 'To' in memory.
2541 UInt_t temp;
2542 const Int_t offset = config->fOffset;
2543 for(; iter != end; iter = (char*)iter + sizeof(void*) ) {
2544 buf >> temp;
2545
2546 if ((temp & kIsReferenced) != 0) {
2547 HandleReferencedTObject(buf,*(void**)iter,config);
2548 }
2549
2550 To *x = (To*)( ((char*) (*(void**)iter) ) + offset );
2551 *x = (To)temp;
2552 }
2553 return 0;
2554 }
2555 };
2556
2557 template <typename From, typename To>
2559 static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *iter, const void *end, const TConfiguration *config)
2560 {
2561 // Simple conversion from a 'From' on disk to a 'To' in memory.
2563 From temp;
2564 const Int_t offset = config->fOffset;
2565 for(; iter != end; iter = (char*)iter + sizeof(void*) ) {
2566 buf.ReadWithFactor(&temp, conf->fFactor, conf->fXmin);
2567 To *x = (To*)( ((char*) (*(void**)iter) ) + offset );
2568 *x = (To)temp;
2569 }
2570 return 0;
2571 }
2572 };
2573
2574 template <typename From, typename To>
2576 static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *iter, const void *end, const TConfiguration *config)
2577 {
2578 // Simple conversion from a 'From' on disk to a 'To' in memory.
2579 TConfNoFactor *conf = (TConfNoFactor *)config;
2580 From temp;
2581 const Int_t offset = config->fOffset;
2582 for(; iter != end; iter = (char*)iter + sizeof(void*) ) {
2583 buf.ReadWithNbits(&temp, conf->fNbits);
2584 To *x = (To*)( ((char*) (*(void**)iter) ) + offset );
2585 *x = (To)temp;
2586 }
2587 return 0;
2588 }
2589 };
2590
2591 template <typename T>
2592 static INLINE_TEMPLATE_ARGS Int_t WriteBasicType(TBuffer &buf, void *iter, const void *end, const TConfiguration *config)
2593 {
2594 const Int_t offset = config->fOffset;
2595
2596 for(; iter != end; iter = (char*)iter + sizeof(void*) ) {
2597 T *x = (T*)( ((char*) (*(void**)iter) ) + offset );
2598 buf << *x;
2599 }
2600 return 0;
2601 }
2602
2603 template <typename To, typename From>
2605 static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *iter, const void *end, const TConfiguration *config)
2606 {
2607 const Int_t offset = config->fOffset;
2608
2609 for(; iter != end; iter = (char*)iter + sizeof(void*) ) {
2610 From *from = (From*)( ((char*) (*(void**)iter) ) + offset );
2611 To to = (To)(*from);
2612 buf << to;
2613 }
2614 return 0;
2615 }
2616 };
2617
2618 template <typename To, typename From>
2620 static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *iter, const void *end, const TConfiguration *config)
2621 {
2622 const Int_t offset = config->fOffset;
2623 const TStreamerElement *elem = config->fCompInfo->fElem;
2624
2625 for(; iter != end; iter = (char*)iter + sizeof(void*) ) {
2626 From *from = (From*)( ((char*) (*(void**)iter) ) + offset );
2627 To to = (To)(*from);
2628 WriteCompressed(buf, &to, elem);
2629 }
2630 return 0;
2631 }
2632 };
2633 template <typename To, typename From>
2635 static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *iter, const void *end, const TConfiguration *config)
2636 {
2637 const Int_t offset = config->fOffset;
2638 const TStreamerElement *elem = config->fCompInfo->fElem;
2639
2640 for(; iter != end; iter = (char*)iter + sizeof(void*) ) {
2641 From *from = (From*)( ((char*) (*(void**)iter) ) + offset );
2642 To to = (To)(*from);
2643 WriteCompressed(buf, &to, elem);
2644 }
2645 return 0;
2646 }
2647 };
2648
2649 static INLINE_TEMPLATE_ARGS Int_t ReadBase(TBuffer &buf, void *start, const void *end, const TConfiguration *config)
2650 {
2651 // Well the implementation is non trivial since we do not have a proxy for the container of _only_ the base class. For now
2652 // punt.
2653
2654 return GenericRead(buf,start,end,config);
2655 }
2656
2657 static INLINE_TEMPLATE_ARGS Int_t WriteBase(TBuffer &buf, void *start, const void *end, const TConfiguration *config)
2658 {
2659 // Well the implementation is non trivial since we do not have a proxy for the container of _only_ the base class. For now
2660 // punt.
2661
2662 return GenericWrite(buf,start,end,config);
2663 }
2664
2665 static inline Int_t ReadStreamerCase(TBuffer &buf, void *start, const void *end, const TConfiguration *config)
2666 {
2667 UInt_t pos, count;
2668 /* Version_t v = */ buf.ReadVersion(&pos, &count, config->fInfo->IsA());
2669
2670 LoopOverCollection< ReadViaExtStreamer >(buf, start, end, config);
2671
2672 buf.CheckByteCount(pos, count, config->fCompInfo->fElem->GetFullName());
2673 return 0;
2674 }
2675
2676 static inline Int_t WriteStreamerCase(TBuffer &buf, void *start, const void *end, const TConfiguration *config)
2677 {
2678 UInt_t pos = buf.WriteVersion(config->fInfo->IsA(), kTRUE);
2679
2680 LoopOverCollection< WriteViaExtStreamer >(buf, start, end, config);
2681
2682 buf.SetByteCount(pos, kTRUE);
2683 return 0;
2684 }
2685
2686 static INLINE_TEMPLATE_ARGS Int_t GenericRead(TBuffer &buf, void *iter, const void *end, const TConfiguration *config)
2687 {
2688 Int_t n = ( ((void**)end) - ((void**)iter) );
2689 char **arr = (char**)iter;
2690 return ((TStreamerInfo*)config->fInfo)->ReadBuffer(buf, arr, &(config->fCompInfo), /*first*/ 0, /*last*/ 1, /*narr*/ n, config->fOffset, 1|2 );
2691 }
2692
2693 static INLINE_TEMPLATE_ARGS Int_t GenericWrite(TBuffer &buf, void *iter, const void *end, const TConfiguration *config)
2694 {
2695 Int_t n = ( ((void**)end) - ((void**)iter) );
2696 char **arr = (char**)iter;
2697 return ((TStreamerInfo*)config->fInfo)->WriteBufferAux(buf, arr, &(config->fCompInfo), /*first*/ 0, /*last*/ 1, n, config->fOffset, 1|2 );
2698 }
2699
2700 };
2701
2703 using LoopAction_t = void (*)(TBuffer&, void *, const void *, Next_t, Int_t, const TStreamerElement *elem);
2704
2705protected:
2706
2707 template <typename T>
2709 {
2710 buf.ReadFastArray((T*)addr, nvalues);
2711 }
2712
2714 {
2715 buf.ReadFastArrayFloat16((float*)addr, nvalues);
2716 }
2717
2719 {
2720 buf.ReadFastArrayDouble32((double*)addr, nvalues);
2721 }
2722
2723 template <typename T>
2725 {
2726 buf << *(T*)addr;
2727 }
2728
2730 {
2731 buf.WriteFloat16((float*)addr, const_cast<TStreamerElement*>(elem));
2732 }
2733
2735 {
2736 buf.WriteDouble32((double*)addr, const_cast<TStreamerElement*>(elem));
2737 }
2738
2739 template <typename T>
2741 {
2742 buf.WriteFastArray((T*)addr, nvalues);
2743 }
2744
2746 {
2747 buf.WriteFastArrayFloat16((float*)addr, nvalues, const_cast<TStreamerElement*>(elem));
2748 }
2749
2751 {
2752 buf.WriteFastArrayDouble32((double*)addr, nvalues, const_cast<TStreamerElement*>(elem));
2753 }
2754
2755 template <typename T,void (*action)(TBuffer&,void *,Int_t)>
2757 {
2758 // Collection of numbers. Memberwise or not, it is all the same.
2759
2760 TConfigSTL *config = (TConfigSTL*)conf;
2761 UInt_t start, count;
2762 /* Version_t vers = */ buf.ReadVersion(&start, &count, config->fOldClass);
2763
2764 TClass *newClass = config->fNewClass;
2765 TVirtualCollectionProxy *newProxy = newClass->GetCollectionProxy();
2767
2768 Int_t nvalues;
2769 buf.ReadInt(nvalues);
2770 void* alternative = newProxy->Allocate(nvalues,true);
2771 if (nvalues) {
2774 void *begin = &(startbuf[0]);
2775 void *end = &(endbuf[0]);
2776 config->fCreateIterators(alternative, &begin, &end, newProxy);
2777 // We can not get here with a split vector of pointer, so we can indeed assume
2778 // that actions->fConfiguration != null.
2779
2780 action(buf,begin,nvalues);
2781
2782 if (begin != &(startbuf[0])) {
2783 // assert(end != endbuf);
2784 config->fDeleteTwoIterators(begin,end);
2785 }
2786 }
2787 newProxy->Commit(alternative);
2788
2789 buf.CheckByteCount(start,count,config->fTypeName);
2790 return 0;
2791 }
2792
2793 template <void (*action)(TBuffer&, void*, const TStreamerElement*)>
2794 static INLINE_TEMPLATE_ARGS void LoopOverCollection(TBuffer &buf, void *iter, const void *end, Next_t next, Int_t /* nvalues */, const TStreamerElement *elem)
2795 {
2796 void *addr;
2797 while( (addr = next(iter, end)) )
2798 {
2799 action(buf, addr, elem);
2800 }
2801 }
2802
2803 template <typename Memory, typename Onfile, void (*action)(TBuffer&, void*, Int_t, const TStreamerElement *elem)>
2804 static INLINE_TEMPLATE_ARGS void ConvertLoopOverCollection(TBuffer &buf, void *iter, const void *end, Next_t next, Int_t nvalues, const TStreamerElement *elem)
2805 {
2806 Onfile *temp = new Onfile[nvalues];
2807 Int_t ind = 0;
2808 void *addr;
2809 while( (addr = next(iter, end)) )
2810 {
2811 temp[ind] = (Onfile)*(Memory*)addr;
2812 ++ind;
2813 }
2814 action(buf, temp, nvalues, elem);
2815 delete [] temp;
2816 }
2817
2818 template <typename T, void (*action)(TBuffer&, void *, const void *, Next_t, Int_t, const TStreamerElement *elem)>
2820 {
2821 // Collection of numbers. Memberwise or not, it is all the same.
2822
2823 TConfigSTL *config = (TConfigSTL*)conf;
2824 UInt_t start = buf.WriteVersion(config->fInfo->IsA(), kTRUE);
2825
2826 TClass *newClass = config->fNewClass;
2827 TVirtualCollectionProxy *newProxy = newClass->GetCollectionProxy();
2828 void *collection = ((char*)addr)+config->fOffset;
2830
2831 Int_t nvalues = newProxy->Size();
2832 buf.WriteInt(nvalues);
2833 if (nvalues) {
2836 void *begin = &(startbuf[0]);
2837 void *end = &(endbuf[0]);
2838 config->fCreateIterators(collection, &begin, &end, newProxy);
2839
2840 action(buf, begin, end, config->fNext, nvalues, config->fCompInfo->fElem);
2841
2842 if (begin != &(startbuf[0])) {
2843 // assert(end != endbuf);
2844 config->fDeleteTwoIterators(begin, end);
2845 }
2846 }
2847 buf.SetByteCount(start);
2848 return 0;
2849 }
2850
2851public:
2856
2861
2866
2871
2872 template <typename T>
2877
2878 template <typename T>
2883
2884 template <typename From, typename To>
2887 {
2888 From *temp = new From[nvalues];
2889 buf.ReadFastArray(temp, nvalues);
2890 To *vec = (To*)addr;
2891 for(Int_t ind = 0; ind < nvalues; ++ind) {
2892 vec[ind] = (To)temp[ind];
2893 }
2894 delete [] temp;
2895 }
2896 };
2897
2898 template <typename From, typename To>
2901 {
2902 From *temp = new From[nvalues];
2903 buf.ReadFastArrayWithNbits(temp, nvalues,0);
2904 To *vec = (To*)addr;
2905 for(Int_t ind = 0; ind < nvalues; ++ind) {
2906 vec[ind] = (To)temp[ind];
2907 }
2908 delete [] temp;
2909 }
2910 };
2911
2912 template <typename From, typename To>
2915 {
2916 From *temp = new From[nvalues];
2917 double factor,min; // needs to be initialized.
2918 buf.ReadFastArrayWithFactor(temp, nvalues, factor, min);
2919 To *vec = (To*)addr;
2920 for(Int_t ind = 0; ind < nvalues; ++ind) {
2921 vec[ind] = (To)temp[ind];
2922 }
2923 delete [] temp;
2924 }
2925 };
2926 template <typename From, typename To>
2933
2934 template <typename Memory, typename Onfile>
2941 template <typename Memory, typename Onfile>
2948
2949 template <typename Memory, typename Onfile>
2956
2957 };
2958
2959 struct GenericLooper : public CollectionLooper<GenericLooper> {
2960 using LoopAction_t = Int_t (*)(TBuffer &, void*, const void *end, const TLoopConfiguration *loopconfig, const TConfiguration*);
2961
2962 template <bool kIsText>
2964 template <bool kIsText>
2966
2967 template <typename T>
2968 static INLINE_TEMPLATE_ARGS Int_t ReadBasicType(TBuffer &buf, void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration *config)
2969 {
2971
2972 Next_t next = loopconfig->fNext;
2973 const Int_t offset = config->fOffset;
2974
2976 void *iter = loopconfig->fCopyIterator(iterator,start);
2977 void *addr;
2978 while( (addr = next(iter,end)) ) {
2979 T *x = (T*)( ((char*)addr) + offset );
2980 buf >> *x;
2981 }
2982 if (iter != &iterator[0]) {
2983 loopconfig->fDeleteIterator(iter);
2984 }
2985 return 0;
2986 }
2987
2988 template <typename T>
2989 static INLINE_TEMPLATE_ARGS Int_t WriteBasicType(TBuffer &buf, void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration *config)
2990 {
2992
2993 Next_t next = loopconfig->fNext;
2994 const Int_t offset = config->fOffset;
2995
2997 void *iter = loopconfig->fCopyIterator(iterator,start);
2998 void *addr;
2999 while( (addr = next(iter,end)) ) {
3000 T *x = (T*)( ((char*)addr) + offset );
3001 buf << *x;
3002 }
3003 if (iter != &iterator[0]) {
3004 loopconfig->fDeleteIterator(iter);
3005 }
3006 return 0;
3007 }
3008
3009 template <typename To, typename From>
3011 static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration *config)
3012 {
3014
3015 Next_t next = loopconfig->fNext;
3016 const Int_t offset = config->fOffset;
3017
3019 void *iter = loopconfig->fCopyIterator(iterator,start);
3020 void *addr;
3021 while( (addr = next(iter,end)) ) {
3022 From *x = (From*)( ((char*)addr) + offset );
3023 To t = (To)(*x);
3024 buf << t;
3025 }
3026 if (iter != &iterator[0]) {
3027 loopconfig->fDeleteIterator(iter);
3028 }
3029 return 0;
3030 }
3031 };
3032
3033 template <Int_t (*iter_action)(TBuffer&,void *,const TConfiguration*)>
3034 static INLINE_TEMPLATE_ARGS Int_t LoopOverCollection(TBuffer &buf, void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration *config)
3035 {
3037
3038 // const Int_t offset = config->fOffset;
3039 Next_t next = loopconfig->fNext;
3040
3042 void *iter = loopconfig->fCopyIterator(&iterator,start);
3043 void *addr;
3044 while( (addr = next(iter,end)) ) {
3045 iter_action(buf, addr, config);
3046 }
3047 if (iter != &iterator[0]) {
3048 loopconfig->fDeleteIterator(iter);
3049 }
3050 return 0;
3051 }
3052
3053 template <typename From, typename To>
3054 struct Generic {
3055 static void ConvertAction(From *items, void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration *config)
3056 {
3058
3059 const Int_t offset = config->fOffset;
3060 Next_t next = loopconfig->fNext;
3061
3063 void *iter = loopconfig->fCopyIterator(&iterator,start);
3064 void *addr;
3065 while( (addr = next(iter,end)) ) {
3066 To *x = (To*)( ((char*)addr) + offset );
3067 *x = (To)(*items);
3068 ++items;
3069 }
3070 if (iter != &iterator[0]) {
3071 loopconfig->fDeleteIterator(iter);
3072 }
3073 }
3074 // ConvertAction used for writing.
3075 static void WriteConvertAction(void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration *config, To *items)
3076 {
3078
3079 const Int_t offset = config->fOffset;
3080 Next_t next = loopconfig->fNext;
3081
3083 void *iter = loopconfig->fCopyIterator(&iterator,start);
3084 void *addr;
3085
3086 while( (addr = next(iter,end)) ) {
3087 From *x = (From*)( ((char*)addr) + offset );
3088 *items = (To)*x;
3089 ++items;
3090 }
3091 if (iter != &iterator[0]) {
3092 loopconfig->fDeleteIterator(iter);
3093 }
3094 }
3095 };
3096
3097 template <typename From, typename To>
3098 struct Numeric {
3099 // ConvertAction used for reading.
3100 static void ConvertAction(From *items, void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration * /* config */)
3101 {
3102 // The difference with ConvertAction is that we can modify the start
3103 // iterator and skip the copy. We also never have an offset.
3104
3106 Next_t next = loopconfig->fNext;
3107
3108 void *iter = start;
3109 void *addr;
3110 while( (addr = next(iter,end)) ) {
3111 To *x = (To*)(addr);
3112 *x = (To)(*items);
3113 ++items;
3114 }
3115 }
3116 // ConvertAction used for writing.
3117 static void WriteConvertAction(void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration * /* config */, To *items)
3118 {
3119 // The difference with ConvertAction is that we can modify the start
3120 // iterator and skip the copy. We also never have an offset.
3121
3123 Next_t next = loopconfig->fNext;
3124
3125 void *iter = start;
3126 void *addr;
3127 while( (addr = next(iter,end)) ) {
3128 From *x = (From*)(addr);
3129 *items = (To)*x;
3130 ++items;
3131 }
3132 }
3133 };
3134
3135 template <typename From, typename To, template <typename F, typename T> class Converter = Generic >
3137 static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration *config)
3138 {
3139 // Simple conversion from a 'From' on disk to a 'To' in memory.
3140
3143 Int_t nvalues = proxy->Size();
3144
3145 From *items = new From[nvalues];
3147 Converter<From,To>::ConvertAction(items,start,end,loopconfig,config);
3148 delete [] items;
3149 return 0;
3150 }
3151 };
3152
3153 template <typename To>
3155 static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration *config)
3156 {
3157 // Simple conversion from a 'From' on disk to a 'To' in memory.
3158
3161 Int_t nvalues = proxy->Size();
3162
3165
3166 const Int_t offset = config->fOffset;
3167 Next_t next = loopconfig->fNext;
3168
3170 void *iter = loopconfig->fCopyIterator(&iterator,start);
3171 void *addr;
3172 while( (addr = next(iter,end)) ) {
3173 buf >> (*items);
3174 if (((*items) & kIsReferenced) != 0) {
3175 HandleReferencedTObject(buf, addr, config);
3176 }
3177 To *x = (To*)( ((char*)addr) + offset );
3178 *x = (To)(*items);
3179 ++items;
3180 }
3181 if (iter != &iterator[0]) {
3182 loopconfig->fDeleteIterator(iter);
3183 }
3184
3185 delete [] items_storage;
3186 return 0;
3187 }
3188 };
3189
3190 template <typename From, typename To, template <typename F, typename T> class Converter >
3192 static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration *config)
3193 {
3194 // Simple conversion from a 'From' on disk to a 'To' in memory.
3195
3198 Int_t nvalues = proxy->Size();
3199
3201
3202 From *items = new From[nvalues];
3203 buf.ReadFastArrayWithFactor(items, nvalues, conf->fFactor, conf->fXmin);
3204 Converter<From,To>::ConvertAction(items,start,end,loopconfig,config);
3205 delete [] items;
3206 return 0;
3207 }
3208 };
3209
3210 template <typename From, typename To, template <typename F, typename T> class Converter >
3212 static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration *config)
3213 {
3214 // Simple conversion from a 'From' on disk to a 'To' in memory.
3215
3218 Int_t nvalues = proxy->Size();
3219
3221
3222 From *items = new From[nvalues];
3224 Converter<From,To>::ConvertAction(items,start,end,loopconfig,config);
3225 delete [] items;
3226 return 0;
3227 }
3228 };
3229
3230 template <typename Onfile, typename Memory, template <typename F, typename T> class Converter = Generic >
3232 static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer &buf, void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration *config)
3233 {
3234 // Simple conversion from a 'From' on disk to a 'To' in memory.
3235
3238 Int_t nvalues = proxy->Size();
3239
3240 Onfile *items = new Onfile[nvalues];
3241 Converter<Memory,Onfile>::WriteConvertAction(start, end, loopconfig, config, items);
3243 delete [] items;
3244 return 0;
3245 }
3246 };
3247
3248 template <typename Onfile, typename Memory, template <typename F, typename T> class Converter >
3250 static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer & /* buf */, void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration *config)
3251 {
3252 // Simple conversion from a 'From' on disk to a 'To' in memory.
3253
3256 Int_t nvalues = proxy->Size();
3257
3259
3260 Onfile *items = new Onfile[nvalues];
3261 Converter<Memory,Onfile>::WriteConvertAction(start, end, loopconfig, config, items);
3262 R__ASSERT(false && "Not yet implemented");
3263 (void)conf;
3264 // buf.WriteFastArrayWithNbits(items, nvalues, conf->fNbits);
3265 delete [] items;
3266 return 0;
3267 }
3268 };
3269
3270 template <typename Onfile, typename Memory, template <typename F, typename T> class Converter >
3272 static INLINE_TEMPLATE_ARGS Int_t Action(TBuffer & /* buf */, void *start, const void *end, const TLoopConfiguration *loopconf, const TConfiguration *config)
3273 {
3274 // Simple conversion from a 'From' on disk to a 'To' in memory.
3275
3278 Int_t nvalues = proxy->Size();
3279
3281
3282 Onfile *items = new Onfile[nvalues];
3283 Converter<Memory,Onfile>::WriteConvertAction(start, end, loopconfig, config, items);
3284 R__ASSERT(false && "Not yet implemented");
3285 (void)conf;
3286 // buf.WriteFastArrayWithNbits(items, nvalues, conf->fNbits);
3287 delete [] items;
3288 return 0;
3289 }
3290 };
3291
3292 static INLINE_TEMPLATE_ARGS Int_t ReadBase(TBuffer &buf, void *start, const void *end, const TLoopConfiguration * loopconfig, const TConfiguration *config)
3293 {
3294 // Well the implementation is non trivial since we do not have a proxy for the container of _only_ the base class. For now
3295 // punt.
3296
3297 return GenericRead(buf,start,end,loopconfig, config);
3298 }
3299
3300 static INLINE_TEMPLATE_ARGS Int_t WriteBase(TBuffer &buf, void *start, const void *end, const TLoopConfiguration * loopconfig, const TConfiguration *config)
3301 {
3302 // Well the implementation is non trivial since we do not have a proxy for the container of _only_ the base class. For now
3303 // punt.
3304
3305 return GenericWrite(buf,start,end,loopconfig, config);
3306 }
3307
3308 static INLINE_TEMPLATE_ARGS Int_t GenericRead(TBuffer &buf, void *, const void *, const TLoopConfiguration * loopconf, const TConfiguration *config)
3309 {
3312 return ((TStreamerInfo*)config->fInfo)->ReadBuffer(buf, *proxy, &(config->fCompInfo), /*first*/ 0, /*last*/ 1, /*narr*/ proxy->Size(), config->fOffset, 1|2 );
3313 }
3314
3315 static INLINE_TEMPLATE_ARGS Int_t GenericWrite(TBuffer &buf, void *, const void *, const TLoopConfiguration * loopconf, const TConfiguration *config)
3316 {
3319 return ((TStreamerInfo*)config->fInfo)->WriteBufferAux(buf, *proxy, &(config->fCompInfo), /*first*/ 0, /*last*/ 1, proxy->Size(), config->fOffset, 1|2 );
3320 }
3321
3322 template <typename T>
3324 {
3325 buf >> *(T*)addr;
3326 }
3327
3329 {
3330 buf.ReadWithNbits((float*)addr,12);
3331 }
3332
3334 {
3335 buf.WriteFloat16((float*)addr, nullptr);
3336 }
3337
3339 {
3340 //we read a float and convert it to double
3342 buf >> afloat;
3343 *(double*)addr = (Double_t)afloat;
3344 }
3345
3347 {
3348 //we read a float and convert it to double
3349 Float_t afloat = (Float_t)*(double*)addr;
3350 buf << afloat;
3351 }
3352
3353 template <typename ActionHolder>
3355 {
3356 // Collection of numbers. Memberwise or not, it is all the same.
3357
3358 TConfigSTL *config = (TConfigSTL*)conf;
3359 UInt_t start, count;
3360 /* Version_t vers = */ buf.ReadVersion(&start, &count, config->fOldClass);
3361
3362 TClass *newClass = config->fNewClass;
3363 TVirtualCollectionProxy *newProxy = newClass->GetCollectionProxy();
3365
3366 Int_t nvalues;
3367 buf.ReadInt(nvalues);
3368 void* alternative = newProxy->Allocate(nvalues,true);
3369 if (nvalues) {
3372 void *begin = &(startbuf[0]);
3373 void *end = &(endbuf[0]);
3374 config->fCreateIterators(alternative, &begin, &end, newProxy);
3375 // We can not get here with a split vector of pointer, so we can indeed assume
3376 // that actions->fConfiguration != null.
3377
3379 ActionHolder::Action(buf,begin,end,&loopconf,config);
3380
3381 if (begin != &(startbuf[0])) {
3382 // assert(end != endbuf);
3383 config->fDeleteTwoIterators(begin,end);
3384 }
3385 }
3386 newProxy->Commit(alternative);
3387
3388 buf.CheckByteCount(start,count,config->fTypeName);
3389 return 0;
3390 }
3391
3392 template <typename ActionHolder>
3394 {
3395 // Collection of numbers. Memberwise or not, it is all the same.
3396
3397 TConfigSTL *config = (TConfigSTL*)conf;
3398 UInt_t start = buf.WriteVersion(config->fInfo->IsA(), kTRUE);
3399
3400 TClass *newClass = config->fNewClass;
3401 TVirtualCollectionProxy *newProxy = newClass->GetCollectionProxy();
3402 void *collection = ((char*)addr)+config->fOffset;
3404
3405 Int_t nvalues = newProxy->Size();
3406 buf.WriteInt(nvalues);
3407 if (nvalues) {
3410 void *begin = &(startbuf[0]);
3411 void *end = &(endbuf[0]);
3412 config->fCreateIterators(collection, &begin, &end, newProxy);
3413 // We can not get here with a split vector of pointer, so we can indeed assume
3414 // that actions->fConfiguration != null.
3415
3417 ActionHolder::Action(buf,begin,end,&loopconf,config);
3418
3419 if (begin != &(startbuf[0])) {
3420 // assert(end != endbuf);
3421 config->fDeleteTwoIterators(begin,end);
3422 }
3423 }
3424
3425 buf.SetByteCount(start);
3426 return 0;
3427 }
3428
3433
3438
3440 {
3442 // Could also use:
3443 // return ReadNumericalCollection<ConvertBasicType<NoFactorMarker<double>,double,Numeric > >(buf,addr,conf);
3444 }
3445
3447 {
3449 // Could also use:
3450 // return ReadNumericalCollection<WriteConvertBasicType<NoFactorMarker<double>, double, Numeric > >(buf,addr,conf);
3451 }
3452
3453 template <typename T>
3455 {
3456 //TODO: Check whether we can implement this without loading the data in
3457 // a temporary variable and whether this is noticeably faster.
3459 }
3460
3461 template <typename T>
3463 {
3464 //TODO: Check whether we can implement this without loading the data in
3465 // a temporary variable and whether this is noticeably faster.
3467 }
3468
3469 template <typename From, typename To>
3472 {
3473 // return ReadNumericalCollection<To,ConvertRead<From,To>::Action >(buf,addr,conf);
3475 }
3476 };
3477
3478 template <typename Memory, typename Onfile>
3481 {
3482 // return ReadNumericalCollection<To,ConvertRead<From,To>::Action >(buf,addr,conf);
3484 }
3485 };
3486 };
3487}
3488
3489// Used in GetCollectionReadAction for the kConv cases within a collection
3490// Not to be confused with GetConvertCollectionReadAction
3491template <typename Looper, typename From>