Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TClonesArray.cxx
Go to the documentation of this file.
1// @(#)root/cont:$Id$
2// Author: Rene Brun 11/02/96
3
4/*************************************************************************
5 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12/** \class TClonesArray
13\ingroup Containers
14An array of clone (identical) objects. Memory for the objects
15stored in the array is allocated only once in the lifetime of the
16clones array. All objects must be of the same class. For the rest
17this class has the same properties as TObjArray.
18
19To reduce the very large number of new and delete calls in large
20loops like this (O(100000) x O(10000) times new/delete):
21~~~ {.cpp}
22 TObjArray a(10000);
23 while (TEvent *ev = (TEvent *)next()) { // O(100000) events
24 for (int i = 0; i < ev->Ntracks; i++) { // O(10000) tracks
25 a[i] = new TTrack(x,y,z,...);
26 ...
27 ...
28 }
29 ...
30 a.Delete();
31 }
32~~~
33One better uses a TClonesArray which reduces the number of
34new/delete calls to only O(10000):
35~~~ {.cpp}
36 TClonesArray a("TTrack", 10000);
37 while (TEvent *ev = (TEvent *)next()) { // O(100000) events
38 for (int i = 0; i < ev->Ntracks; i++) { // O(10000) tracks
39 new(a[i]) TTrack(x,y,z,...);
40 ...
41 ...
42 }
43 ...
44 a.Delete(); // or a.Clear() or a.Clear("C")
45 }
46~~~
47To reduce the number of call to the constructor (especially useful
48if the user class requires memory allocation), the object can be
49added (and constructed when needed) using ConstructedAt which only
50calls the constructor once per slot.
51~~~ {.cpp}
52 TClonesArray a("TTrack", 10000);
53 while (TEvent *ev = (TEvent *)next()) { // O(100000) events
54 for (int i = 0; i < ev->Ntracks; i++) { // O(10000) tracks
55 TTrack *track = (TTrack*)a.ConstructedAt(i);
56 track->Set(x,y,z,....);
57 ...
58 ...
59 }
60 ...
61 a.Clear(); // or a.Clear("C");
62 }
63~~~
64Note: the only supported way to add objects to a TClonesArray is
65via the new with placement method or the ConstructedAt method.
66The other Add() methods ofTObjArray and its base classes are not
67allowed.
68
69Considering that a new/delete costs about 70 mus on a 300 MHz HP,
70O(10^9) new/deletes will save about 19 hours.
71
72### NOTE 1
73
74C/C++ offers the possibility of allocating and deleting memory.
75Forgetting to delete allocated memory is a programming error called a
76"memory leak", i.e. the memory of your process grows and eventually
77your program crashes. Even if you *always* delete the allocated
78memory, the recovered space may not be efficiently reused. The
79process knows that there are portions of free memory, but when you
80allocate it again, a fresh piece of memory is grabbed. Your program
81is free from semantic errors, but the total memory of your process
82still grows, because your program's memory is full of "holes" which
83reduce the efficiency of memory access; this is called "memory
84fragmentation". Moreover new / delete are expensive operations in
85terms of CPU time.
86
87Without entering into technical details, TClonesArray allows you to
88"reuse" the same portion of memory for new/delete avoiding memory
89fragmentation and memory growth and improving the performance by
90orders of magnitude. Every time the memory of the TClonesArray has
91to be reused, the Clear() method is used. To provide its benefits,
92each TClonesArray must be allocated *once* per process and disposed
93of (deleted) *only when not needed any more*.
94
95So a job should see *only one* deletion for each TClonesArray,
96which should be Clear()ed during the job several times. Deleting a
97TClonesArray is a double waste. Not only you do not avoid memory
98fragmentation, but you worsen it because the TClonesArray itself
99is a rather heavy structure, and there is quite some code in the
100destructor, so you have more memory fragmentation and slower code.
101
102### NOTE 2
103
104When investigating misuse of TClonesArray, please make sure of the following:
105
106 - Use Clear() or Clear("C") instead of Delete(). This will improve
107 program execution time.
108 - TClonesArray object classes containing pointers allocate memory.
109 To avoid causing memory leaks, special Clear("C") must be used
110 for clearing TClonesArray. When option "C" is specified, ROOT
111 automatically executes the Clear() method (by default it is
112 empty contained in TObject). This method must be overridden in
113 the relevant TClonesArray object class, implementing the reset
114 procedure for pointer objects.
115 - If the objects are added using the placement new then the Clear must
116 deallocate the memory.
117 - If the objects are added using TClonesArray::ConstructedAt then the
118 heap-based memory can stay allocated and reused as the constructor is
119 not called for already constructed/added object.
120 - To reduce memory fragmentation, please make sure that the
121 TClonesArrays are not destroyed and created on every event. They
122 must only be constructed/destructed at the beginning/end of the
123 run.
124*/
125
126#include "TClonesArray.h"
127
128#include "TError.h"
129#include "TROOT.h"
130#include "TBuffer.h"
131#include "TClass.h"
132#include "TObject.h"
133#include "TObjectTable.h"
134#include "snprintf.h"
135
136#include <cstdlib>
137
139
140// To allow backward compatibility of TClonesArray of v5 TF1 objects
141// that were stored member-wise.
142using Updater_t = void (*)(Int_t nobjects, TObject **from, TObject **to);
145
148 return true;
149}
150
153 return true;
154}
155
156/// Internal Utility routine to correctly release the memory for an object
157static inline void R__ReleaseMemory(TClass *cl, TObject *obj)
158{
159 if (obj && ! obj->IsDestructed()) {
160 // -- The TObject destructor has not been called.
161 cl->Destructor(obj);
162 } else {
163 // -- The TObject destructor was called, just free memory.
164 //
165 // remove any possible entries from the ObjectTable
168 }
169 ::operator delete(obj);
170 }
171}
172
173
174////////////////////////////////////////////////////////////////////////////////
175/// Default Constructor.
176
178{
179 fClass = nullptr;
180 fKeep = nullptr;
181}
182
183////////////////////////////////////////////////////////////////////////////////
184/// Create an array of clone objects of classname. The class must inherit from
185/// TObject.
186/// The second argument s indicates an approximate number of objects
187/// that will be entered in the array. If more than s objects are entered,
188/// the array will be automatically expanded.
189///
190/// The third argument is not used anymore and only there for backward
191/// compatibility reasons.
192
193TClonesArray::TClonesArray(const char *classname, Int_t s, Bool_t) : TObjArray(s)
194{
195 fKeep = nullptr;
196 SetClass(classname,s);
197}
198
199////////////////////////////////////////////////////////////////////////////////
200/// Create an array of clone objects of class cl. The class must inherit from
201/// TObject.
202/// The second argument, s, indicates an approximate number of objects
203/// that will be entered in the array. If more than s objects are entered,
204/// the array will be automatically expanded.
205///
206/// The third argument is not used anymore and only there for backward
207/// compatibility reasons.
208
210{
211 fKeep = nullptr;
212 SetClass(cl,s);
213}
214
215////////////////////////////////////////////////////////////////////////////////
216/// Copy ctor.
217
219{
220 fKeep = new TObjArray(tc.fSize);
221 fClass = tc.fClass;
222
224
225 for (Int_t i = 0; i < fSize; i++) {
226 if (tc.fCont[i]) fCont[i] = tc.fCont[i]->Clone();
227 fKeep->fCont[i] = fCont[i];
228 }
229}
230
231////////////////////////////////////////////////////////////////////////////////
232/// Assignment operator.
233
235{
236 if (this == &tc) return *this;
237
238 if (fClass != tc.fClass) {
239 Error("operator=", "cannot copy TClonesArray's when classes are different");
240 return *this;
241 }
242
243 if (tc.fSize > fSize)
245
246 Int_t i;
247
248 for (i = 0; i < fSize; i++)
249 if (fKeep->fCont[i]) {
251 fKeep->fCont[i] = nullptr;
252 fCont[i] = nullptr;
253 }
254
256
257 for (i = 0; i < tc.fSize; i++) {
258 if (tc.fCont[i]) fKeep->fCont[i] = tc.fCont[i]->Clone();
259 fCont[i] = fKeep->fCont[i];
260 }
261
262 fLast = tc.fLast;
263 Changed();
264 return *this;
265}
266
267////////////////////////////////////////////////////////////////////////////////
268/// Delete a clones array.
269
271{
272 if (fKeep) {
273 for (Int_t i = 0; i < fKeep->fSize; i++) {
275 fKeep->fCont[i] = nullptr;
276 }
277 }
279
280 // Protect against erroneously setting of owner bit
282}
283
284////////////////////////////////////////////////////////////////////////////////
285/// When the kBypassStreamer bit is set, the automatically
286/// generated Streamer can call directly TClass::WriteBuffer.
287/// Bypassing the Streamer improves the performance when writing/reading
288/// the objects in the TClonesArray. However there is a drawback:
289/// When a TClonesArray is written with split=0 bypassing the Streamer,
290/// the StreamerInfo of the class in the array being optimized,
291/// one cannot use later the TClonesArray with split>0. For example,
292/// there is a problem with the following scenario:
293/// 1. A class Foo has a TClonesArray of Bar objects
294/// 2. The Foo object is written with split=0 to Tree T1.
295/// In this case the StreamerInfo for the class Bar is created
296/// in optimized mode in such a way that data members of the same type
297/// are written as an array improving the I/O performance.
298/// 3. In a new program, T1 is read and a new Tree T2 is created
299/// with the object Foo in split>1
300/// 4. When the T2 branch is created, the StreamerInfo for the class Bar
301/// is created with no optimization (mandatory for the split mode).
302/// The optimized Bar StreamerInfo is going to be used to read
303/// the TClonesArray in T1. The result will be Bar objects with
304/// data member values not in the right sequence.
305/// The solution to this problem is to call BypassStreamer(kFALSE)
306/// for the TClonesArray. In this case, the normal Bar::Streamer function
307/// will be called. The Bar::Streamer function works OK independently
308/// if the Bar StreamerInfo had been generated in optimized mode or not.
309
311{
312 if (bypass)
314 else
316}
317
318////////////////////////////////////////////////////////////////////////////////
319/// Remove empty slots from array.
320
322{
323 Int_t j = 0, je = 0;
324
325 TObject **tmp = new TObject* [fSize];
326
327 for (Int_t i = 0; i < fSize; i++) {
328 if (fCont[i]) {
329 fCont[j] = fCont[i];
330 fKeep->fCont[j] = fKeep->fCont[i];
331 j++;
332 } else {
333 tmp[je] = fKeep->fCont[i];
334 je++;
335 }
336 }
337
338 fLast = j - 1;
339
340 Int_t jf = 0;
341 for ( ; j < fSize; j++) {
342 fCont[j] = nullptr;
343 fKeep->fCont[j] = tmp[jf];
344 jf++;
345 }
346
347 delete [] tmp;
348
349 R__ASSERT(je == jf);
350}
351
352////////////////////////////////////////////////////////////////////////////////
353/// Get an object at index 'idx' that is guaranteed to have been constructed.
354/// It might be either a freshly allocated object or one that had already been
355/// allocated (and assumingly used). In the later case, it is the callers
356/// responsibility to insure that the object is returned to a known state,
357/// usually by calling the Clear method on the TClonesArray.
358///
359/// Tests to see if the destructor has been called on the object.
360/// If so, or if the object has never been constructed the class constructor is called using
361/// New(). If not, return a pointer to the correct memory location.
362/// This explicitly to deal with TObject classes that allocate memory
363/// which will be reset (but not deallocated) in their Clear()
364/// functions.
365
367{
368 TObject *obj = (*this)[idx];
369 if ( obj && ! obj->IsDestructed() ) {
370 return obj;
371 }
372 return (fClass) ? static_cast<TObject*>(fClass->New(obj)) : nullptr;
373}
374
375////////////////////////////////////////////////////////////////////////////////
376/// Get an object at index 'idx' that is guaranteed to have been constructed.
377/// It might be either a freshly allocated object or one that had already been
378/// allocated (and assumingly used). In the later case, the function Clear
379/// will be called and passed the value of 'clear_options'
380///
381/// Tests to see if the destructor has been called on the object.
382/// If so, or if the object has never been constructed the class constructor is called using
383/// New(). If not, return a pointer to the correct memory location.
384/// This explicitly to deal with TObject classes that allocate memory
385/// which will be reset (but not deallocated) in their Clear()
386/// functions.
387
389{
390 TObject *obj = (*this)[idx];
391 if ( obj && !obj->IsDestructed() ) {
392 obj->Clear(clear_options);
393 return obj;
394 }
395 return (fClass) ? static_cast<TObject*>(fClass->New(obj)) : nullptr;
396}
397
398////////////////////////////////////////////////////////////////////////////////
399/// Clear the clones array. Only use this routine when your objects don't
400/// allocate memory since it will not call the object dtors.
401/// However, if the class in the TClonesArray implements the function
402/// Clear(Option_t *option) and if option = "C" the function Clear()
403/// is called for all objects in the array. In the function Clear(), one
404/// can delete objects or dynamic arrays allocated in the class.
405/// This procedure is much faster than calling TClonesArray::Delete().
406/// When the option starts with "C+", eg "C+xyz" the objects in the array
407/// are in turn cleared with the option "xyz"
408
410{
411 if (option && option[0] == 'C') {
412 const char *cplus = strstr(option,"+");
413 if (cplus) {
414 cplus = cplus + 1;
415 } else {
416 cplus = "";
417 }
419 for (Int_t i = 0; i < n; i++) {
420 TObject *obj = UncheckedAt(i);
421 if (obj) {
422 obj->Clear(cplus);
423 obj->ResetBit( kHasUUID );
424 obj->ResetBit( kIsReferenced );
425 obj->SetUniqueID( 0 );
426 }
427 }
428 }
429
430 // Protect against erroneously setting of owner bit
432
434}
435
436////////////////////////////////////////////////////////////////////////////////
437/// Clear the clones array. Use this routine when your objects allocate
438/// memory (e.g. objects inheriting from TNamed or containing TStrings
439/// allocate memory). If not you better use Clear() since if is faster.
440
442{
444 {
445 // In case of emulated class, we can not use the delete operator
446 // directly, it would use the wrong destructor.
447 for (Int_t i = 0; i < fSize; i++) {
448 if (fCont[i] && ! fCont[i]->IsDestructed()) {
450 }
451 }
452 } else {
453 for (Int_t i = 0; i < fSize; i++) {
454 if (fCont[i] && ! fCont[i]->IsDestructed()) {
455 fCont[i]->~TObject();
456 }
457 }
458 }
459
460 // Protect against erroneously setting of owner bit.
462
464}
465
466////////////////////////////////////////////////////////////////////////////////
467/// Expand or shrink the array to newSize elements.
468
470{
471 if (newSize < 0) {
472 Error ("Expand", "newSize must be positive (%d)", newSize);
473 return;
474 }
475 if (!fKeep) {
476 Error("ExpandCreate", "Not initialized properly, fKeep is still a nullptr");
477 return;
478 }
479 if (newSize == fSize)
480 return;
481 if (newSize < fSize) {
482 // release allocated space in fKeep and set to 0 so
483 // Expand() will shrink correctly
484 for (int i = newSize; i < fSize; i++)
485 if (fKeep->fCont[i]) {
487 fKeep->fCont[i] = nullptr;
488 }
489 }
490
491 TObjArray::Expand(newSize);
492 fKeep->Expand(newSize);
493}
494
495////////////////////////////////////////////////////////////////////////////////
496/// Expand or shrink the array to n elements and create the clone
497/// objects by calling their default ctor. If n is less than the current size
498/// the array is shrunk and the allocated space is freed.
499/// This routine is typically used to create a clonesarray into which
500/// one can directly copy object data without going via the
501/// "new (arr[i]) MyObj()" (i.e. the vtbl is already set correctly).
502
504{
505 if (n < 0) {
506 Error("ExpandCreate", "n must be positive (%d)", n);
507 return;
508 }
509 if (!fKeep) {
510 Error("ExpandCreate", "Not initialized properly, fKeep is still a nullptr");
511 return;
512 }
513 if (n > fSize)
515
516 Int_t i;
517 for (i = 0; i < n; i++) {
518 if (!fKeep->fCont[i]) {
519 fKeep->fCont[i] = (TObject*)fClass->New();
520 } else if (fKeep->fCont[i]->IsDestructed()) {
521 // The object has been deleted (or never initialized)
522 fClass->New(fKeep->fCont[i]);
523 }
524 fCont[i] = fKeep->fCont[i];
525 }
526
527 for (i = n; i < fSize; i++)
528 if (fKeep->fCont[i]) {
530 fKeep->fCont[i] = nullptr;
531 fCont[i] = nullptr;
532 }
533
534 fLast = n - 1;
535 Changed();
536}
537
538////////////////////////////////////////////////////////////////////////////////
539/// Expand or shrink the array to n elements and create the clone
540/// objects by calling their default ctor. If n is less than the current size
541/// the array is shrunk but the allocated space is _not_ freed.
542/// This routine is typically used to create a clonesarray into which
543/// one can directly copy object data without going via the
544/// "new (arr[i]) MyObj()" (i.e. the vtbl is already set correctly).
545/// This is a simplified version of ExpandCreate used in the TTree mechanism.
546
548{
549 Int_t oldSize = fKeep->GetSize();
550 if (n > fSize)
552
553 Int_t i;
554 for (i = 0; i < n; i++) {
555 if (i >= oldSize || !fKeep->fCont[i]) {
556 fKeep->fCont[i] = (TObject*)fClass->New();
557 } else if (fKeep->fCont[i]->IsDestructed()) {
558 // The object has been deleted (or never initialized)
559 fClass->New(fKeep->fCont[i]);
560 }
561 fCont[i] = fKeep->fCont[i];
562 }
563 if (fLast >= n) {
564 memset(fCont + n, 0, (fLast - n + 1) * sizeof(TObject*));
565 }
566 fLast = n - 1;
567 Changed();
568}
569
570////////////////////////////////////////////////////////////////////////////////
571/// Remove object at index idx.
572
574{
575 if (!BoundsOk("RemoveAt", idx)) return nullptr;
576
577 int i = idx-fLowerBound;
578
579 if (fCont[i] && ! fCont[i]->IsDestructed()) {
580 fCont[i]->~TObject();
581 }
582
583 if (fCont[i]) {
584 fCont[i] = nullptr;
585 // recalculate array size
586 if (i == fLast)
587 do { fLast--; } while (fLast >= 0 && !fCont[fLast]);
588 Changed();
589 }
590
591 return nullptr;
592}
593
594////////////////////////////////////////////////////////////////////////////////
595/// Remove object from array.
596
598{
599 if (!obj) return nullptr;
600
601 Int_t i = IndexOf(obj) - fLowerBound;
602
603 if (i == -1) return nullptr;
604
605 if (fCont[i] && ! fCont[i]->IsDestructed()) {
606 fCont[i]->~TObject();
607 }
608
609 fCont[i] = nullptr;
610 // recalculate array size
611 if (i == fLast)
612 do { fLast--; } while (fLast >= 0 && !fCont[fLast]);
613 Changed();
614 return obj;
615}
616
617////////////////////////////////////////////////////////////////////////////////
618/// Remove objects from index idx1 to idx2 included.
619
621{
622 if (!BoundsOk("RemoveRange", idx1)) return;
623 if (!BoundsOk("RemoveRange", idx2)) return;
624
625 idx1 -= fLowerBound;
626 idx2 -= fLowerBound;
627
628 Bool_t change = kFALSE;
629 for (TObject **obj = fCont+idx1; obj <= fCont+idx2; obj++) {
630 if (!*obj) continue;
631 if (!(*obj)->IsDestructed()) {
632 (*obj)->~TObject();
633 }
634 *obj = nullptr;
635 change = kTRUE;
636 }
637
638 // recalculate array size
639 if (change) Changed();
640 if (idx1 < fLast || fLast > idx2) return;
641 do { fLast--; } while (fLast >= 0 && !fCont[fLast]);
642}
643
644////////////////////////////////////////////////////////////////////////////////
645/// Create an array of clone objects of class cl. The class must inherit from
646/// TObject.
647/// The second argument s indicates an approximate number of objects
648/// that will be entered in the array. If more than s objects are entered,
649/// the array will be automatically expanded.
650///
651/// NB: This function should not be called in the TClonesArray is already
652/// initialized with a class.
653
655{
656 if (fKeep) {
657 Error("SetClass", "TClonesArray already initialized with another class");
658 return;
659 }
660 fClass = (TClass*)cl;
661 if (!fClass) {
662 MakeZombie();
663 Error("SetClass", "called with a null pointer");
664 return;
665 }
666 const char *classname = fClass->GetName();
667 if (!fClass->IsTObject()) {
668 MakeZombie();
669 Error("SetClass", "%s does not inherit from TObject", classname);
670 return;
671 }
673 MakeZombie();
674 Error("SetClass", "%s must inherit from TObject as the left most base class.", classname);
675 return;
676 }
677 Int_t nch = strlen(classname)+2;
678 char *name = new char[nch];
679 snprintf(name,nch, "%ss", classname);
680 SetName(name);
681 delete [] name;
682
683 fKeep = new TObjArray(s);
684
686}
687
688////////////////////////////////////////////////////////////////////////////////
689///see TClonesArray::SetClass(const TClass*)
690
691void TClonesArray::SetClass(const char *classname, Int_t s)
692{
693 SetClass(TClass::GetClass(classname),s);
694}
695
696
697////////////////////////////////////////////////////////////////////////////////
698/// A TClonesArray is always the owner of the object it contains.
699/// However the collection its inherits from (TObjArray) does not.
700/// Hence this member function needs to be a nop for TClonesArray.
701
703{
704 // Nothing to be done.
705}
706
707////////////////////////////////////////////////////////////////////////////////
708/// If objects in array are sortable (i.e. IsSortable() returns true
709/// for all objects) then sort array.
710
712{
714 if (nentries <= 0 || fSorted) return;
715 for (Int_t i = 0; i < fSize; i++)
716 if (fCont[i]) {
717 if (!fCont[i]->IsSortable()) {
718 Error("Sort", "objects in array are not sortable");
719 return;
720 }
721 }
722
724
725 fLast = -2;
726 fSorted = kTRUE;
727}
728
729////////////////////////////////////////////////////////////////////////////////
730/// Write all objects in array to the I/O buffer. ATTENTION: empty slots
731/// are also stored (using one byte per slot). If you don't want this
732/// use a TOrdCollection or TList.
733
735{
736 // Important Note: if you modify this function, remember to also modify
737 // TConvertClonesArrayToProxy accordingly
738
739 Int_t nobjects;
740 char nch;
741 TString s, classv;
742 UInt_t R__s, R__c;
743
744 if (b.IsReading()) {
745 Version_t v = b.ReadVersion(&R__s, &R__c);
746 if (v == 3) {
747 const Int_t kOldBypassStreamer = BIT(14);
748 if (TestBit(kOldBypassStreamer)) BypassStreamer();
749 }
750 if (v > 2)
752 if (v > 1)
754 s.Streamer(b);
755 classv = s;
756 Int_t clv = 0;
757 Ssiz_t pos = s.Index(";");
758 if (pos != kNPOS) {
759 classv = s(0, pos);
760 s = s(pos+1, s.Length()-pos-1);
761 clv = s.Atoi();
762 }
763 TClass *cl = TClass::GetClass(classv);
764 if (!cl) {
765 Error("Streamer", "expecting class %s but it was not found by TClass::GetClass\n",
766 classv.Data());
767 b.CheckByteCount(R__s, R__c,TClonesArray::IsA());
768 return;
769 }
770
771 b >> nobjects;
772 if (nobjects < 0)
773 nobjects = -nobjects; // still there for backward compatibility
774 b >> fLowerBound;
775 if (!fClass) {
776 fClass = cl;
777 if (!fKeep) {
778 fKeep = new TObjArray(fSize);
779 Expand(nobjects);
780 }
781 } else if (cl != fClass && classv == fClass->GetName()) {
782 // If fClass' name is different from classv, the user has intentionally changed
783 // the target class, so we must not override it.
784 fClass = cl;
785 //this case may happen when switching from an emulated class to the real class
786 //may not be an error. fClass may point to a deleted object
787 //Error("Streamer", "expecting objects of type %s, finding objects"
788 // " of type %s", fClass->GetName(), cl->GetName());
789 //return;
790 }
791
792 // make sure there are enough slots in the fKeep array
793 if (fKeep->GetSize() < nobjects)
794 Expand(nobjects);
795
796 //reset fLast. nobjects may be 0
797 Int_t oldLast = fLast;
798 fLast = nobjects-1;
799
800 //TStreamerInfo *sinfo = fClass->GetStreamerInfo(clv);
802 for (Int_t i = 0; i < nobjects; i++) {
803 if (!fKeep->fCont[i]) {
804 fKeep->fCont[i] = (TObject*)fClass->New();
805 } else if (fKeep->fCont[i]->IsDestructed()) {
806 // The object has been deleted (or never initialized)
807 fClass->New(fKeep->fCont[i]);
808 }
809
810 fCont[i] = fKeep->fCont[i];
811 }
812 if (clv < 8 && classv == "TF1") {
813 // To allow backward compatibility of TClonesArray of v5 TF1 objects
814 // that were stored member-wise.
815 TClonesArray temp("ROOT::v5::TF1Data");
816 temp.ExpandCreate(nobjects);
817 b.ReadClones(&temp, nobjects, clv);
818 // And now covert the v5 into the current
820 gClonesArrayTF1Updater(nobjects, temp.GetObjectRef(nullptr), this->GetObjectRef(nullptr));
821 } else if (clv <= 8 && clv > 3 && clv != 6 && classv == "TFormula") {
822 // To allow backwar compatibility of TClonesArray of v5 TF1 objects
823 // that were stored member-wise.
824 TClonesArray temp("ROOT::v5::TFormula");
825 temp.ExpandCreate(nobjects);
826 b.ReadClones(&temp, nobjects, clv);
827 // And now covert the v5 into the current
829 gClonesArrayTFormulaUpdater(nobjects, temp.GetObjectRef(nullptr), this->GetObjectRef(nullptr));
830 } else {
831 // sinfo->ReadBufferClones(b,this,nobjects,-1,0);
832 b.ReadClones(this, nobjects, clv);
833 }
834 } else {
835 for (Int_t i = 0; i < nobjects; i++) {
836 b >> nch;
837 if (nch) {
838 if (!fKeep->fCont[i])
839 fKeep->fCont[i] = (TObject*)fClass->New();
840 else if (fKeep->fCont[i]->IsDestructed()) {
841 // The object has been deleted (or never initialized)
842 fClass->New(fKeep->fCont[i]);
843 }
844
845 fCont[i] = fKeep->fCont[i];
846 b.StreamObject(fKeep->fCont[i]);
847 }
848 }
849 }
850 for (Int_t i = TMath::Max(nobjects,0); i < oldLast+1; ++i) fCont[i] = nullptr;
851 Changed();
852 b.CheckByteCount(R__s, R__c,TClonesArray::IsA());
853 } else {
854 //Make sure TStreamerInfo is not optimized, otherwise it will not be
855 //possible to support schema evolution in read mode.
856 //In case the StreamerInfo has already been computed and optimized,
857 //one must disable the option BypassStreamer
858 b.ForceWriteInfoClones(this);
859
860 // make sure the status of bypass streamer is part of the buffer
861 // (bits in TObject), so that when reading the object the right
862 // mode is used, independent of the method (e.g. written via
863 // TMessage, received and stored to a file and then later read via
864 // TBufferFile)
865 Bool_t bypass = kFALSE;
867 bypass = CanBypassStreamer();
869 }
870
871 R__c = b.WriteVersion(TClonesArray::IsA(), kTRUE);
874 s.Form("%s;%d", fClass->GetName(), fClass->GetClassVersion());
875 s.Streamer(b);
876 nobjects = GetEntriesFast();
877 b << nobjects;
878 b << fLowerBound;
879 if (CanBypassStreamer()) {
880 b.WriteClones(this,nobjects);
881 } else {
882 for (Int_t i = 0; i < nobjects; i++) {
883 if (!fCont[i]) {
884 nch = 0;
885 b << nch;
886 } else {
887 nch = 1;
888 b << nch;
889 b.StreamObject(fCont[i]);
890 }
891 }
892 }
893 b.SetByteCount(R__c, kTRUE);
894
895 if (bypass)
897 }
898}
899
900////////////////////////////////////////////////////////////////////////////////
901/// Return pointer to reserved area in which a new object of clones
902/// class can be constructed. This operator should not be used for
903/// lefthand side assignments, like a[2] = xxx. Only like,
904/// new (a[2]) myClass, or xxx = a[2]. Of course right hand side usage
905/// is only legal after the object has been constructed via the
906/// new operator or via the New() method. To remove elements from
907/// the clones array use Remove() or RemoveAt().
908
910{
911 if (idx < 0) {
912 Error("operator[]", "out of bounds at %d in %zx", idx, (size_t)this);
913 return fCont[0];
914 }
915 if (!fClass) {
916 Error("operator[]", "invalid class specified in TClonesArray ctor");
917 return fCont[0];
918 }
919 if (idx >= fSize)
920 Expand(TMath::Max(idx+1, GrowBy(fSize)));
921
922 if (!fKeep->fCont[idx]) {
924 // Reset the bit so that:
925 // obj = myClonesArray[i];
926 // ! obj->IsDestructed()
927 // will behave correctly.
928 // TObject::kNotDeleted is one of the higher bit that is not settable via the public
929 // interface. But luckily we are its friend.
930 fKeep->fCont[idx]->fBits &= ~kNotDeleted;
931 }
932 fCont[idx] = fKeep->fCont[idx];
933
934 fLast = TMath::Max(idx, GetAbsLast());
935 Changed();
936
937 return fCont[idx];
938}
939
940////////////////////////////////////////////////////////////////////////////////
941/// Return the object at position idx. Returns 0 if idx is out of bounds.
942
944{
945 if (idx < 0 || idx >= fSize) {
946 Error("operator[]", "out of bounds at %d in %zx", idx, (size_t)this);
947 return nullptr;
948 }
949
950 return fCont[idx];
951}
952
953////////////////////////////////////////////////////////////////////////////////
954/// Create an object of type fClass with the default ctor at the specified
955/// index. Returns 0 in case of error.
956
958{
959 if (idx < 0) {
960 Error("New", "out of bounds at %d in %zx", idx, (size_t)this);
961 return nullptr;
962 }
963 if (!fClass) {
964 Error("New", "invalid class specified in TClonesArray ctor");
965 return nullptr;
966 }
967
968 return (TObject *)fClass->New(operator[](idx));
969}
970
971//______________________________________________________________________________
972//
973// The following functions are utilities implemented by Jason Detwiler
974// (jadetwiler@lbl.gov)
975//
976////////////////////////////////////////////////////////////////////////////////
977/// Directly move the object pointers from tc without cloning (copying).
978/// This TClonesArray takes over ownership of all of tc's object
979/// pointers. The tc array is left empty upon return.
980
982{
983 // tests
984 if (!tc || tc == this || tc->GetEntriesFast() == 0) return;
985 AbsorbObjects(tc, 0, tc->GetEntriesFast() - 1);
986}
987
988////////////////////////////////////////////////////////////////////////////////
989/// Directly move the range of object pointers from tc without cloning
990/// (copying).
991/// This TClonesArray takes over ownership of all of tc's object pointers
992/// from idx1 to idx2. The tc array is re-arranged by return.
993
995{
996 // tests
997 if (!tc || tc == this || tc->GetEntriesFast() == 0) return;
998 if (fClass != tc->fClass) {
999 Error("AbsorbObjects", "cannot absorb objects when classes are different");
1000 return;
1001 }
1002
1003 if (idx1 > idx2) {
1004 Error("AbsorbObjects", "range is not valid: idx1>idx2");
1005 return;
1006 }
1007 if (idx2 >= tc->GetEntriesFast()) {
1008 Error("AbsorbObjects", "range is not valid: idx2 out of bounds");
1009 return;
1010 }
1011
1012 // cache the sorted status
1013 Bool_t wasSorted = IsSorted() && tc->IsSorted() &&
1014 (!Last() || Last()->Compare(tc->First()) == -1);
1015
1016 // expand this
1017 Int_t oldSize = GetEntriesFast();
1018 Int_t newSize = oldSize + (idx2-idx1+1);
1019 if(newSize > fSize)
1020 Expand(newSize);
1021
1022 // move
1023 for (Int_t i = idx1; i <= idx2; i++) {
1024 Int_t newindex = oldSize+i -idx1;
1025 fCont[newindex] = tc->fCont[i];
1026 R__ReleaseMemory(fClass,fKeep->fCont[newindex]);
1027 (*fKeep)[newindex] = (*(tc->fKeep))[i];
1028 tc->fCont[i] = nullptr;
1029 (*(tc->fKeep))[i] = nullptr;
1030 }
1031
1032 // cleanup
1033 for (Int_t i = idx2+1; i < tc->GetEntriesFast(); i++) {
1034 tc->fCont[i-(idx2-idx1+1)] = tc->fCont[i];
1035 (*(tc->fKeep))[i-(idx2-idx1+1)] = (*(tc->fKeep))[i];
1036 tc->fCont[i] = nullptr;
1037 (*(tc->fKeep))[i] = nullptr;
1038 }
1039 tc->fLast = tc->GetEntriesFast() - 2 - (idx2 - idx1);
1040 fLast = newSize-1;
1041 if (!wasSorted)
1042 Changed();
1043}
1044
1045////////////////////////////////////////////////////////////////////////////////
1046/// Sort multiple TClonesArrays simultaneously with this array.
1047/// If objects in array are sortable (i.e. IsSortable() returns true
1048/// for all objects) then sort array.
1049
1051{
1053 if (nentries <= 1 || fSorted) return;
1054 Bool_t sortedCheck = kTRUE;
1055 for (Int_t i = 0; i < fSize; i++) {
1056 if (fCont[i]) {
1057 if (!fCont[i]->IsSortable()) {
1058 Error("MultiSort", "objects in array are not sortable");
1059 return;
1060 }
1061 }
1062 if (sortedCheck && i > 1) {
1063 if (ObjCompare(fCont[i], fCont[i-1]) < 0) sortedCheck = kFALSE;
1064 }
1065 }
1066 if (sortedCheck) {
1067 fSorted = kTRUE;
1068 return;
1069 }
1070
1071 for (int i = 0; i < nTCs; i++) {
1072 if (tcs[i] == this) {
1073 Error("MultiSort", "tcs[%d] = \"this\"", i);
1074 return;
1075 }
1076 if (tcs[i]->GetEntriesFast() != GetEntriesFast()) {
1077 Error("MultiSort", "tcs[%d] has length %d != length of this (%d)",
1078 i, tcs[i]->GetEntriesFast(), this->GetEntriesFast());
1079 return;
1080 }
1081 }
1082
1083 int nBs = nTCs*2+1;
1084 TObject*** b = new TObject**[nBs];
1085 for (int i = 0; i < nTCs; i++) {
1086 b[2*i] = tcs[i]->fCont;
1087 b[2*i+1] = tcs[i]->fKeep->fCont;
1088 }
1089 b[nBs-1] = fKeep->fCont;
1090 QSort(fCont, nBs, b, 0, TMath::Min(nentries, upto-fLowerBound));
1091 delete [] b;
1092
1093 fLast = -2;
1094 fSorted = kTRUE;
1095}
#define SafeDelete(p)
Definition RConfig.hxx:525
#define b(i)
Definition RSha256.hxx:100
int Int_t
Definition RtypesCore.h:45
short Version_t
Definition RtypesCore.h:65
constexpr Bool_t kFALSE
Definition RtypesCore.h:101
constexpr Ssiz_t kNPOS
Definition RtypesCore.h:124
constexpr Bool_t kTRUE
Definition RtypesCore.h:100
const char Option_t
Definition RtypesCore.h:66
#define BIT(n)
Definition Rtypes.h:85
#define ClassImp(name)
Definition Rtypes.h:377
void(*)(Int_t nobjects, TObject **from, TObject **to) Updater_t
Updater_t gClonesArrayTFormulaUpdater
Updater_t gClonesArrayTF1Updater
static void R__ReleaseMemory(TClass *cl, TObject *obj)
Internal Utility routine to correctly release the memory for an object.
bool R__SetClonesArrayTFormulaUpdater(Updater_t func)
bool R__SetClonesArrayTF1Updater(Updater_t func)
#define R__ASSERT(e)
Definition TError.h:118
Option_t Option_t option
char name[80]
Definition TGX11.cxx:110
int nentries
R__EXTERN TObjectTable * gObjectTable
#define snprintf
Definition civetweb.c:1540
Buffer base class used for serializing objects.
Definition TBuffer.h:43
@ kCannotHandleMemberWiseStreaming
Definition TBuffer.h:76
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:81
EState GetState() const
Definition TClass.h:488
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition TClass.cxx:4978
void Destructor(void *obj, Bool_t dtorOnly=kFALSE)
Explicitly call destructor for object.
Definition TClass.cxx:5400
Int_t Size() const
Return size of object of this class.
Definition TClass.cxx:5704
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition TClass.cxx:5938
Int_t GetBaseClassOffset(const TClass *toBase, void *address=nullptr, bool isDerivedObject=true)
Definition TClass.cxx:2791
@ kEmulated
Definition TClass.h:125
Version_t GetClassVersion() const
Definition TClass.h:420
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition TClass.cxx:2968
An array of clone (identical) objects.
TObjArray * fKeep
Pointer to the class of the elements.
TObject *& operator[](Int_t idx) override
Return pointer to reserved area in which a new object of clones class can be constructed.
TClass * IsA() const override
void BypassStreamer(Bool_t bypass=kTRUE)
When the kBypassStreamer bit is set, the automatically generated Streamer can call directly TClass::W...
virtual ~TClonesArray()
Delete a clones array.
void AbsorbObjects(TClonesArray *tc)
Directly move the object pointers from tc without cloning (copying).
virtual void ExpandCreateFast(Int_t n)
Expand or shrink the array to n elements and create the clone objects by calling their default ctor.
void Expand(Int_t newSize) override
Expand or shrink the array to newSize elements.
TObject * RemoveAt(Int_t idx) override
Remove object at index idx.
void SetClass(const char *classname, Int_t size=1000)
see TClonesArray::SetClass(const TClass*)
Bool_t CanBypassStreamer() const
void Clear(Option_t *option="") override
Clear the clones array.
void Delete(Option_t *option="") override
Clear the clones array.
TClass * fClass
TClonesArray & operator=(const TClonesArray &tc)
Assignment operator.
void Sort(Int_t upto=kMaxInt) override
If objects in array are sortable (i.e.
void Streamer(TBuffer &) override
Write all objects in array to the I/O buffer.
void RemoveRange(Int_t idx1, Int_t idx2) override
Remove objects from index idx1 to idx2 included.
TObject * ConstructedAt(Int_t idx)
Get an object at index 'idx' that is guaranteed to have been constructed.
virtual void ExpandCreate(Int_t n)
Expand or shrink the array to n elements and create the clone objects by calling their default ctor.
TClonesArray()
Default Constructor.
void Compress() override
Remove empty slots from array.
void SetOwner(Bool_t enable=kTRUE) override
A TClonesArray is always the owner of the object it contains.
TObject * New(Int_t idx)
Create an object of type fClass with the default ctor at the specified index.
TObject * Remove(TObject *obj) override
Remove object from array.
void MultiSort(Int_t nTCs, TClonesArray **tcs, Int_t upto=kMaxInt)
Sort multiple TClonesArrays simultaneously with this array.
virtual Int_t GrowBy(Int_t delta) const
Increase the collection's capacity by delta slots.
void SetName(const char *name)
TString fName
Bool_t IsSortable() const override
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
const char * GetName() const override
Returns name of object.
Definition TNamed.h:47
An array of TObjects.
Definition TObjArray.h:31
Int_t GetEntriesFast() const
Definition TObjArray.h:58
TObject ** fCont
Definition TObjArray.h:37
Int_t IndexOf(const TObject *obj) const override
virtual void Expand(Int_t newSize)
Expand or shrink the array to newSize elements.
TObject ** GetObjectRef() const
Definition TObjArray.h:63
TObject * Last() const override
Return the object in the last filled slot. Returns 0 if no entries.
void Clear(Option_t *option="") override
Remove all objects from the array.
Bool_t BoundsOk(const char *where, Int_t at) const
Definition TObjArray.h:157
TObject * UncheckedAt(Int_t i) const
Definition TObjArray.h:84
TObject * First() const override
Return the object in the first slot.
Int_t fLowerBound
Array contents.
Definition TObjArray.h:38
Int_t GetAbsLast() const
Return absolute index to last object in array.
Int_t fLast
Definition TObjArray.h:39
void RemoveQuietly(TObject *obj)
Remove an object from the object table.
Mother of all ROOT objects.
Definition TObject.h:41
virtual void Clear(Option_t *="")
Definition TObject.h:119
Bool_t IsDestructed() const
IsDestructed.
Definition TObject.h:178
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition TObject.h:199
virtual TObject * Clone(const char *newname="") const
Make a clone of an object using the Streamer facility.
Definition TObject.cxx:223
UInt_t fBits
bit field status word
Definition TObject.h:45
virtual void Streamer(TBuffer &)
Stream an object of class TObject.
Definition TObject.cxx:888
static TClass * Class()
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition TObject.cxx:780
static Bool_t GetObjectStat()
Get status of object stat flag.
Definition TObject.cxx:1061
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:987
virtual void SetUniqueID(UInt_t uid)
Set the unique object id.
Definition TObject.cxx:791
virtual Int_t Compare(const TObject *obj) const
Compare abstract method.
Definition TObject.cxx:238
void MakeZombie()
Definition TObject.h:53
virtual ~TObject()
TObject destructor.
Definition TObject.cxx:158
void ResetBit(UInt_t f)
Definition TObject.h:198
@ kHasUUID
if object has a TUUID (its fUniqueID=UUIDNumber)
Definition TObject.h:66
@ kIsReferenced
if object is referenced by a TRef or TRefArray
Definition TObject.h:65
virtual Bool_t IsSorted() const
virtual void Changed()
static void QSort(TObject **a, Int_t first, Int_t last)
Sort array of TObject pointers using a quicksort algorithm.
static Int_t ObjCompare(TObject *a, TObject *b)
Compare to objects in the collection. Use member Compare() of object a.
static void * ObjectAlloc(size_t size)
Used to allocate a TObject on the heap (via TObject::operator new()).
Definition TStorage.cxx:291
Basic string class.
Definition TString.h:139
Ssiz_t Length() const
Definition TString.h:417
Int_t Atoi() const
Return integer value of string.
Definition TString.cxx:1988
const char * Data() const
Definition TString.h:376
virtual void Streamer(TBuffer &)
Stream a string object.
Definition TString.cxx:1412
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition TString.cxx:2356
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition TString.h:651
const Int_t n
Definition legend1.C:16
Short_t Max(Short_t a, Short_t b)
Returns the largest of a and b.
Definition TMathBase.h:250
Short_t Min(Short_t a, Short_t b)
Returns the smallest of a and b.
Definition TMathBase.h:198