Logo ROOT   6.16/01
Reference Guide
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 "TClass.h"
131#include "TObject.h"
132#include "TObjectTable.h"
133
134#include <stdlib.h>
135
137
138// To allow backward compatibility of TClonesArray of v5 TF1 objects
139// that were stored member-wise.
140using Updater_t = void (*)(Int_t nobjects, TObject **from, TObject **to);
143
146 return true;
147}
148
151 return true;
152}
153
154/// Internal Utility routine to correctly release the memory for an object
155static inline void R__ReleaseMemory(TClass *cl, TObject *obj)
156{
157 if (obj && obj->TestBit(TObject::kNotDeleted)) {
158 // -- The TObject destructor has not been called.
159 cl->Destructor(obj);
160 } else {
161 // -- The TObject destructor was called, just free memory.
162 //
163 // remove any possible entries from the ObjectTable
166 }
167 ::operator delete(obj);
168 }
169}
170
171
172////////////////////////////////////////////////////////////////////////////////
173/// Default Constructor.
174
176{
177 fClass = 0;
178 fKeep = 0;
179}
180
181////////////////////////////////////////////////////////////////////////////////
182/// Create an array of clone objects of classname. The class must inherit from
183/// TObject.
184/// The second argument s indicates an approximate number of objects
185/// that will be entered in the array. If more than s objects are entered,
186/// the array will be automatically expanded.
187///
188/// The third argument is not used anymore and only there for backward
189/// compatibility reasons.
190
192{
193 fKeep = 0;
194 SetClass(classname,s);
195}
196
197////////////////////////////////////////////////////////////////////////////////
198/// Create an array of clone objects of class cl. The class must inherit from
199/// TObject.
200/// The second argument, s, indicates an approximate number of objects
201/// that will be entered in the array. If more than s objects are entered,
202/// the array will be automatically expanded.
203///
204/// The third argument is not used anymore and only there for backward
205/// compatibility reasons.
206
208{
209 fKeep = 0;
210 SetClass(cl,s);
211}
212
213////////////////////////////////////////////////////////////////////////////////
214/// Copy ctor.
215
217{
218 fKeep = new TObjArray(tc.fSize);
219 fClass = tc.fClass;
220
222
223 for (Int_t i = 0; i < fSize; i++) {
224 if (tc.fCont[i]) fCont[i] = tc.fCont[i]->Clone();
225 fKeep->fCont[i] = fCont[i];
226 }
227}
228
229////////////////////////////////////////////////////////////////////////////////
230/// Assignment operator.
231
233{
234 if (this == &tc) return *this;
235
236 if (fClass != tc.fClass) {
237 Error("operator=", "cannot copy TClonesArray's when classes are different");
238 return *this;
239 }
240
241 if (tc.fSize > fSize)
243
244 Int_t i;
245
246 for (i = 0; i < fSize; i++)
247 if (fKeep->fCont[i]) {
249 fKeep->fCont[i] = nullptr;
250 fCont[i] = nullptr;
251 }
252
254
255 for (i = 0; i < tc.fSize; i++) {
256 if (tc.fCont[i]) fKeep->fCont[i] = tc.fCont[i]->Clone();
257 fCont[i] = fKeep->fCont[i];
258 }
259
260 fLast = tc.fLast;
261 Changed();
262 return *this;
263}
264
265////////////////////////////////////////////////////////////////////////////////
266/// Delete a clones array.
267
269{
270 if (fKeep) {
271 for (Int_t i = 0; i < fKeep->fSize; i++) {
273 fKeep->fCont[i] = nullptr;
274 }
275 }
277
278 // Protect against erroneously setting of owner bit
280}
281
282////////////////////////////////////////////////////////////////////////////////
283/// When the kBypassStreamer bit is set, the automatically
284/// generated Streamer can call directly TClass::WriteBuffer.
285/// Bypassing the Streamer improves the performance when writing/reading
286/// the objects in the TClonesArray. However there is a drawback:
287/// When a TClonesArray is written with split=0 bypassing the Streamer,
288/// the StreamerInfo of the class in the array being optimized,
289/// one cannot use later the TClonesArray with split>0. For example,
290/// there is a problem with the following scenario:
291/// 1. A class Foo has a TClonesArray of Bar objects
292/// 2. The Foo object is written with split=0 to Tree T1.
293/// In this case the StreamerInfo for the class Bar is created
294/// in optimized mode in such a way that data members of the same type
295/// are written as an array improving the I/O performance.
296/// 3. In a new program, T1 is read and a new Tree T2 is created
297/// with the object Foo in split>1
298/// 4. When the T2 branch is created, the StreamerInfo for the class Bar
299/// is created with no optimization (mandatory for the split mode).
300/// The optimized Bar StreamerInfo is going to be used to read
301/// the TClonesArray in T1. The result will be Bar objects with
302/// data member values not in the right sequence.
303/// The solution to this problem is to call BypassStreamer(kFALSE)
304/// for the TClonesArray. In this case, the normal Bar::Streamer function
305/// will be called. The Bar::Streamer function works OK independently
306/// if the Bar StreamerInfo had been generated in optimized mode or not.
307
309{
310 if (bypass)
312 else
314}
315
316////////////////////////////////////////////////////////////////////////////////
317/// Remove empty slots from array.
318
320{
321 Int_t j = 0, je = 0;
322
323 TObject **tmp = new TObject* [fSize];
324
325 for (Int_t i = 0; i < fSize; i++) {
326 if (fCont[i]) {
327 fCont[j] = fCont[i];
328 fKeep->fCont[j] = fKeep->fCont[i];
329 j++;
330 } else {
331 tmp[je] = fKeep->fCont[i];
332 je++;
333 }
334 }
335
336 fLast = j - 1;
337
338 Int_t jf = 0;
339 for ( ; j < fSize; j++) {
340 fCont[j] = 0;
341 fKeep->fCont[j] = tmp[jf];
342 jf++;
343 }
344
345 delete [] tmp;
346
347 R__ASSERT(je == jf);
348}
349
350////////////////////////////////////////////////////////////////////////////////
351/// Get an object at index 'idx' that is guaranteed to have been constructed.
352/// It might be either a freshly allocated object or one that had already been
353/// allocated (and assumingly used). In the later case, it is the callers
354/// responsibility to insure that the object is returned to a known state,
355/// usually by calling the Clear method on the TClonesArray.
356///
357/// Tests to see if the destructor has been called on the object.
358/// If so, or if the object has never been constructed the class constructor is called using
359/// New(). If not, return a pointer to the correct memory location.
360/// This explicitly to deal with TObject classes that allocate memory
361/// which will be reset (but not deallocated) in their Clear()
362/// functions.
363
365{
366 TObject *obj = (*this)[idx];
367 if ( obj && obj->TestBit(TObject::kNotDeleted) ) {
368 return obj;
369 }
370 return (fClass) ? static_cast<TObject*>(fClass->New(obj)) : 0;
371}
372
373////////////////////////////////////////////////////////////////////////////////
374/// Get an object at index 'idx' that is guaranteed to have been constructed.
375/// It might be either a freshly allocated object or one that had already been
376/// allocated (and assumingly used). In the later case, the function Clear
377/// will be called and passed the value of 'clear_options'
378///
379/// Tests to see if the destructor has been called on the object.
380/// If so, or if the object has never been constructed the class constructor is called using
381/// New(). If not, return a pointer to the correct memory location.
382/// This explicitly to deal with TObject classes that allocate memory
383/// which will be reset (but not deallocated) in their Clear()
384/// functions.
385
387{
388 TObject *obj = (*this)[idx];
389 if ( obj && obj->TestBit(TObject::kNotDeleted) ) {
390 obj->Clear(clear_options);
391 return obj;
392 }
393 return (fClass) ? static_cast<TObject*>(fClass->New(obj)) : 0;
394}
395
396////////////////////////////////////////////////////////////////////////////////
397/// Clear the clones array. Only use this routine when your objects don't
398/// allocate memory since it will not call the object dtors.
399/// However, if the class in the TClonesArray implements the function
400/// Clear(Option_t *option) and if option = "C" the function Clear()
401/// is called for all objects in the array. In the function Clear(), one
402/// can delete objects or dynamic arrays allocated in the class.
403/// This procedure is much faster than calling TClonesArray::Delete().
404/// When the option starts with "C+", eg "C+xyz" the objects in the array
405/// are in turn cleared with the option "xyz"
406
408{
409 if (option && option[0] == 'C') {
410 const char *cplus = strstr(option,"+");
411 if (cplus) {
412 cplus = cplus + 1;
413 } else {
414 cplus = "";
415 }
417 for (Int_t i = 0; i < n; i++) {
418 TObject *obj = UncheckedAt(i);
419 if (obj) {
420 obj->Clear(cplus);
421 obj->ResetBit( kHasUUID );
422 obj->ResetBit( kIsReferenced );
423 obj->SetUniqueID( 0 );
424 }
425 }
426 }
427
428 // Protect against erroneously setting of owner bit
430
432}
433
434////////////////////////////////////////////////////////////////////////////////
435/// Clear the clones array. Use this routine when your objects allocate
436/// memory (e.g. objects inheriting from TNamed or containing TStrings
437/// allocate memory). If not you better use Clear() since if is faster.
438
440{
442 // In case of emulated class, we can not use the delete operator
443 // directly, it would use the wrong destructor.
444 for (Int_t i = 0; i < fSize; i++) {
445 if (fCont[i] && fCont[i]->TestBit(kNotDeleted)) {
447 }
448 }
449 } else {
450 for (Int_t i = 0; i < fSize; i++) {
451 if (fCont[i] && fCont[i]->TestBit(kNotDeleted)) {
452 fCont[i]->~TObject();
453 }
454 }
455 }
456
457 // Protect against erroneously setting of owner bit.
459
461}
462
463////////////////////////////////////////////////////////////////////////////////
464/// Expand or shrink the array to newSize elements.
465
467{
468 if (newSize < 0) {
469 Error ("Expand", "newSize must be positive (%d)", newSize);
470 return;
471 }
472 if (!fKeep) {
473 Error("ExpandCreate", "Not initialized properly, fKeep is still a nullptr");
474 return;
475 }
476 if (newSize == fSize)
477 return;
478 if (newSize < fSize) {
479 // release allocated space in fKeep and set to 0 so
480 // Expand() will shrink correctly
481 for (int i = newSize; i < fSize; i++)
482 if (fKeep->fCont[i]) {
484 fKeep->fCont[i] = nullptr;
485 }
486 }
487
488 TObjArray::Expand(newSize);
489 fKeep->Expand(newSize);
490}
491
492////////////////////////////////////////////////////////////////////////////////
493/// Expand or shrink the array to n elements and create the clone
494/// objects by calling their default ctor. If n is less than the current size
495/// the array is shrunk and the allocated space is freed.
496/// This routine is typically used to create a clonesarray into which
497/// one can directly copy object data without going via the
498/// "new (arr[i]) MyObj()" (i.e. the vtbl is already set correctly).
499
501{
502 if (n < 0) {
503 Error("ExpandCreate", "n must be positive (%d)", n);
504 return;
505 }
506 if (!fKeep) {
507 Error("ExpandCreate", "Not initialized properly, fKeep is still a nullptr");
508 return;
509 }
510 if (n > fSize)
512
513 Int_t i;
514 for (i = 0; i < n; i++) {
515 if (!fKeep->fCont[i]) {
516 fKeep->fCont[i] = (TObject*)fClass->New();
517 } else if (!fKeep->fCont[i]->TestBit(kNotDeleted)) {
518 // The object has been deleted (or never initialized)
519 fClass->New(fKeep->fCont[i]);
520 }
521 fCont[i] = fKeep->fCont[i];
522 }
523
524 for (i = n; i < fSize; i++)
525 if (fKeep->fCont[i]) {
527 fKeep->fCont[i] = nullptr;
528 fCont[i] = nullptr;
529 }
530
531 fLast = n - 1;
532 Changed();
533}
534
535////////////////////////////////////////////////////////////////////////////////
536/// Expand or shrink the array to n elements and create the clone
537/// objects by calling their default ctor. If n is less than the current size
538/// the array is shrunk but the allocated space is _not_ freed.
539/// This routine is typically used to create a clonesarray into which
540/// one can directly copy object data without going via the
541/// "new (arr[i]) MyObj()" (i.e. the vtbl is already set correctly).
542/// This is a simplified version of ExpandCreate used in the TTree mechanism.
543
545{
546 Int_t oldSize = fKeep->GetSize();
547 if (n > fSize)
549
550 Int_t i;
551 for (i = 0; i < n; i++) {
552 if (i >= oldSize || !fKeep->fCont[i]) {
553 fKeep->fCont[i] = (TObject*)fClass->New();
554 } else if (!fKeep->fCont[i]->TestBit(kNotDeleted)) {
555 // The object has been deleted (or never initialized)
556 fClass->New(fKeep->fCont[i]);
557 }
558 fCont[i] = fKeep->fCont[i];
559 }
560 if (fLast >= n) {
561 memset(fCont + n, 0, (fLast - n + 1) * sizeof(TObject*));
562 }
563 fLast = n - 1;
564 Changed();
565}
566
567////////////////////////////////////////////////////////////////////////////////
568/// Remove object at index idx.
569
571{
572 if (!BoundsOk("RemoveAt", idx)) return 0;
573
574 int i = idx-fLowerBound;
575
576 if (fCont[i] && fCont[i]->TestBit(kNotDeleted)) {
577 fCont[i]->~TObject();
578 }
579
580 if (fCont[i]) {
581 fCont[i] = 0;
582 // recalculate array size
583 if (i == fLast)
584 do { fLast--; } while (fLast >= 0 && fCont[fLast] == 0);
585 Changed();
586 }
587
588 return 0;
589}
590
591////////////////////////////////////////////////////////////////////////////////
592/// Remove object from array.
593
595{
596 if (!obj) return 0;
597
598 Int_t i = IndexOf(obj) - fLowerBound;
599
600 if (i == -1) return 0;
601
602 if (fCont[i] && fCont[i]->TestBit(kNotDeleted)) {
603 fCont[i]->~TObject();
604 }
605
606 fCont[i] = 0;
607 // recalculate array size
608 if (i == fLast)
609 do { fLast--; } while (fLast >= 0 && fCont[fLast] == 0);
610 Changed();
611 return obj;
612}
613
614////////////////////////////////////////////////////////////////////////////////
615/// Remove objects from index idx1 to idx2 included.
616
618{
619 if (!BoundsOk("RemoveRange", idx1)) return;
620 if (!BoundsOk("RemoveRange", idx2)) return;
621
622 idx1 -= fLowerBound;
623 idx2 -= fLowerBound;
624
625 Bool_t change = kFALSE;
626 for (TObject **obj=fCont+idx1; obj<=fCont+idx2; obj++) {
627 if (!*obj) continue;
628 if ((*obj)->TestBit(kNotDeleted)) {
629 (*obj)->~TObject();
630 }
631 *obj = 0;
632 change = kTRUE;
633 }
634
635 // recalculate array size
636 if (change) Changed();
637 if (idx1 < fLast || fLast > idx2) return;
638 do { fLast--; } while (fLast >= 0 && fCont[fLast] == 0);
639}
640
641////////////////////////////////////////////////////////////////////////////////
642/// Create an array of clone objects of class cl. The class must inherit from
643/// TObject.
644/// The second argument s indicates an approximate number of objects
645/// that will be entered in the array. If more than s objects are entered,
646/// the array will be automatically expanded.
647///
648/// NB: This function should not be called in the TClonesArray is already
649/// initialized with a class.
650
652{
653 if (fKeep) {
654 Error("SetClass", "TClonesArray already initialized with another class");
655 return;
656 }
657 fClass = (TClass*)cl;
658 if (!fClass) {
659 MakeZombie();
660 Error("SetClass", "called with a null pointer");
661 return;
662 }
663 const char *classname = fClass->GetName();
664 if (!fClass->IsTObject()) {
665 MakeZombie();
666 Error("SetClass", "%s does not inherit from TObject", classname);
667 return;
668 }
670 MakeZombie();
671 Error("SetClass", "%s must inherit from TObject as the left most base class.", classname);
672 return;
673 }
674 Int_t nch = strlen(classname)+2;
675 char *name = new char[nch];
676 snprintf(name,nch, "%ss", classname);
677 SetName(name);
678 delete [] name;
679
680 fKeep = new TObjArray(s);
681
683}
684
685////////////////////////////////////////////////////////////////////////////////
686///see TClonesArray::SetClass(const TClass*)
687
688void TClonesArray::SetClass(const char *classname, Int_t s)
689{
690 SetClass(TClass::GetClass(classname),s);
691}
692
693
694////////////////////////////////////////////////////////////////////////////////
695/// A TClonesArray is always the owner of the object it contains.
696/// However the collection its inherits from (TObjArray) does not.
697/// Hence this member function needs to be a nop for TClonesArray.
698
700{
701 // Nothing to be done.
702}
703
704////////////////////////////////////////////////////////////////////////////////
705/// If objects in array are sortable (i.e. IsSortable() returns true
706/// for all objects) then sort array.
707
709{
711 if (nentries <= 0 || fSorted) return;
712 for (Int_t i = 0; i < fSize; i++)
713 if (fCont[i]) {
714 if (!fCont[i]->IsSortable()) {
715 Error("Sort", "objects in array are not sortable");
716 return;
717 }
718 }
719
721
722 fLast = -2;
723 fSorted = kTRUE;
724}
725
726////////////////////////////////////////////////////////////////////////////////
727/// Write all objects in array to the I/O buffer. ATTENTION: empty slots
728/// are also stored (using one byte per slot). If you don't want this
729/// use a TOrdCollection or TList.
730
731void TClonesArray::Streamer(TBuffer &b)
732{
733 // Important Note: if you modify this function, remember to also modify
734 // TConvertClonesArrayToProxy accordingly
735
736 Int_t nobjects;
737 char nch;
738 TString s, classv;
739 UInt_t R__s, R__c;
740
741 if (b.IsReading()) {
742 Version_t v = b.ReadVersion(&R__s, &R__c);
743 if (v == 3) {
744 const Int_t kOldBypassStreamer = BIT(14);
745 if (TestBit(kOldBypassStreamer)) BypassStreamer();
746 }
747 if (v > 2)
748 TObject::Streamer(b);
749 if (v > 1)
750 fName.Streamer(b);
751 s.Streamer(b);
752 classv = s;
753 Int_t clv = 0;
754 Ssiz_t pos = s.Index(";");
755 if (pos != kNPOS) {
756 classv = s(0, pos);
757 s = s(pos+1, s.Length()-pos-1);
758 clv = s.Atoi();
759 }
760 TClass *cl = TClass::GetClass(classv);
761 if (!cl) {
762 printf("TClonesArray::Streamer expecting class %s\n", classv.Data());
763 b.CheckByteCount(R__s, R__c,TClonesArray::IsA());
764 return;
765 }
766
767 b >> nobjects;
768 if (nobjects < 0)
769 nobjects = -nobjects; // still there for backward compatibility
770 b >> fLowerBound;
771 if (fClass == 0 && fKeep == 0) {
772 fClass = cl;
773 fKeep = new TObjArray(fSize);
774 Expand(nobjects);
775 }
776 if (cl != fClass) {
777 fClass = cl;
778 //this case may happen when switching from an emulated class to the real class
779 //may not be an error. fClass may point to a deleted object
780 //Error("Streamer", "expecting objects of type %s, finding objects"
781 // " of type %s", fClass->GetName(), cl->GetName());
782 //return;
783 }
784
785 // make sure there are enough slots in the fKeep array
786 if (fKeep->GetSize() < nobjects)
787 Expand(nobjects);
788
789 //reset fLast. nobjects may be 0
790 Int_t oldLast = fLast;
791 fLast = nobjects-1;
792
793 //TStreamerInfo *sinfo = fClass->GetStreamerInfo(clv);
795 for (Int_t i = 0; i < nobjects; i++) {
796 if (!fKeep->fCont[i]) {
797 fKeep->fCont[i] = (TObject*)fClass->New();
798 } else if (!fKeep->fCont[i]->TestBit(kNotDeleted)) {
799 // The object has been deleted (or never initialized)
800 fClass->New(fKeep->fCont[i]);
801 }
802
803 fCont[i] = fKeep->fCont[i];
804 }
805 if (clv < 8 && classv == "TF1") {
806 // To allow backward compatibility of TClonesArray of v5 TF1 objects
807 // that were stored member-wise.
808 TClonesArray temp("ROOT::v5::TF1Data");
809 temp.ExpandCreate(nobjects);
810 b.ReadClones(&temp, nobjects, clv);
811 // And now covert the v5 into the current
813 gClonesArrayTF1Updater(nobjects, temp.GetObjectRef(nullptr), this->GetObjectRef(nullptr));
814 } else if (clv <= 8 && clv > 3 && clv != 6 && classv == "TFormula") {
815 // To allow backwar compatibility of TClonesArray of v5 TF1 objects
816 // that were stored member-wise.
817 TClonesArray temp("ROOT::v5::TFormula");
818 temp.ExpandCreate(nobjects);
819 b.ReadClones(&temp, nobjects, clv);
820 // And now covert the v5 into the current
822 gClonesArrayTFormulaUpdater(nobjects, temp.GetObjectRef(nullptr), this->GetObjectRef(nullptr));
823 } else {
824 // sinfo->ReadBufferClones(b,this,nobjects,-1,0);
825 b.ReadClones(this, nobjects, clv);
826 }
827 } else {
828 for (Int_t i = 0; i < nobjects; i++) {
829 b >> nch;
830 if (nch) {
831 if (!fKeep->fCont[i])
832 fKeep->fCont[i] = (TObject*)fClass->New();
833 else if (!fKeep->fCont[i]->TestBit(kNotDeleted)) {
834 // The object has been deleted (or never initialized)
835 fClass->New(fKeep->fCont[i]);
836 }
837
838 fCont[i] = fKeep->fCont[i];
839 b.StreamObject(fKeep->fCont[i]);
840 }
841 }
842 }
843 for (Int_t i = TMath::Max(nobjects,0); i < oldLast+1; ++i) fCont[i] = 0;
844 Changed();
845 b.CheckByteCount(R__s, R__c,TClonesArray::IsA());
846 } else {
847 //Make sure TStreamerInfo is not optimized, otherwise it will not be
848 //possible to support schema evolution in read mode.
849 //In case the StreamerInfo has already been computed and optimized,
850 //one must disable the option BypassStreamer
851 b.ForceWriteInfoClones(this);
852
853 // make sure the status of bypass streamer is part of the buffer
854 // (bits in TObject), so that when reading the object the right
855 // mode is used, independent of the method (e.g. written via
856 // TMessage, received and stored to a file and then later read via
857 // TBufferFile)
858 Bool_t bypass = kFALSE;
860 bypass = CanBypassStreamer();
862 }
863
864 R__c = b.WriteVersion(TClonesArray::IsA(), kTRUE);
865 TObject::Streamer(b);
866 fName.Streamer(b);
867 s.Form("%s;%d", fClass->GetName(), fClass->GetClassVersion());
868 s.Streamer(b);
869 nobjects = GetEntriesFast();
870 b << nobjects;
871 b << fLowerBound;
872 if (CanBypassStreamer()) {
873 b.WriteClones(this,nobjects);
874 } else {
875 for (Int_t i = 0; i < nobjects; i++) {
876 if (!fCont[i]) {
877 nch = 0;
878 b << nch;
879 } else {
880 nch = 1;
881 b << nch;
882 b.StreamObject(fCont[i]);
883 }
884 }
885 }
886 b.SetByteCount(R__c, kTRUE);
887
888 if (bypass)
890 }
891}
892
893////////////////////////////////////////////////////////////////////////////////
894/// Return pointer to reserved area in which a new object of clones
895/// class can be constructed. This operator should not be used for
896/// lefthand side assignments, like a[2] = xxx. Only like,
897/// new (a[2]) myClass, or xxx = a[2]. Of course right hand side usage
898/// is only legal after the object has been constructed via the
899/// new operator or via the New() method. To remove elements from
900/// the clones array use Remove() or RemoveAt().
901
903{
904 if (idx < 0) {
905 Error("operator[]", "out of bounds at %d in %lx", idx, (Long_t)this);
906 return fCont[0];
907 }
908 if (!fClass) {
909 Error("operator[]", "invalid class specified in TClonesArray ctor");
910 return fCont[0];
911 }
912 if (idx >= fSize)
913 Expand(TMath::Max(idx+1, GrowBy(fSize)));
914
915 if (!fKeep->fCont[idx]) {
917 // Reset the bit so that:
918 // obj = myClonesArray[i];
919 // obj->TestBit(TObject::kNotDeleted)
920 // will behave correctly.
921 // TObject::kNotDeleted is one of the higher bit that is not settable via the public
922 // interface. But luckily we are its friend.
923 fKeep->fCont[idx]->fBits &= ~kNotDeleted;
924 }
925 fCont[idx] = fKeep->fCont[idx];
926
927 fLast = TMath::Max(idx, GetAbsLast());
928 Changed();
929
930 return fCont[idx];
931}
932
933////////////////////////////////////////////////////////////////////////////////
934/// Return the object at position idx. Returns 0 if idx is out of bounds.
935
937{
938 if (idx < 0 || idx >= fSize) {
939 Error("operator[]", "out of bounds at %d in %lx", idx, (Long_t)this);
940 return 0;
941 }
942
943 return fCont[idx];
944}
945
946////////////////////////////////////////////////////////////////////////////////
947/// Create an object of type fClass with the default ctor at the specified
948/// index. Returns 0 in case of error.
949
951{
952 if (idx < 0) {
953 Error("New", "out of bounds at %d in %lx", idx, (Long_t)this);
954 return 0;
955 }
956 if (!fClass) {
957 Error("New", "invalid class specified in TClonesArray ctor");
958 return 0;
959 }
960
961 return (TObject *)fClass->New(operator[](idx));
962}
963
964//______________________________________________________________________________
965//
966// The following functions are utilities implemented by Jason Detwiler
967// (jadetwiler@lbl.gov)
968//
969////////////////////////////////////////////////////////////////////////////////
970/// Directly move the object pointers from tc without cloning (copying).
971/// This TClonesArray takes over ownership of all of tc's object
972/// pointers. The tc array is left empty upon return.
973
975{
976 // tests
977 if (tc == 0 || tc == this || tc->GetEntriesFast() == 0) return;
978 AbsorbObjects(tc, 0, tc->GetEntriesFast() - 1);
979}
980
981////////////////////////////////////////////////////////////////////////////////
982/// Directly move the range of object pointers from tc without cloning
983/// (copying).
984/// This TClonesArray takes over ownership of all of tc's object pointers
985/// from idx1 to idx2. The tc array is re-arranged by return.
986
988{
989 // tests
990 if (tc == 0 || tc == this || tc->GetEntriesFast() == 0) return;
991 if (fClass != tc->fClass) {
992 Error("AbsorbObjects", "cannot absorb objects when classes are different");
993 return;
994 }
995
996 if (idx1 > idx2) {
997 Error("AbsorbObjects", "range is not valid: idx1>idx2");
998 return;
999 }
1000 if (idx2 >= tc->GetEntriesFast()) {
1001 Error("AbsorbObjects", "range is not valid: idx2 out of bounds");
1002 return;
1003 }
1004
1005 // cache the sorted status
1006 Bool_t wasSorted = IsSorted() && tc->IsSorted() &&
1007 (Last() == 0 || Last()->Compare(tc->First()) == -1);
1008
1009 // expand this
1010 Int_t oldSize = GetEntriesFast();
1011 Int_t newSize = oldSize + (idx2-idx1+1);
1012 if(newSize > fSize)
1013 Expand(newSize);
1014
1015 // move
1016 for (Int_t i = idx1; i <= idx2; i++) {
1017 Int_t newindex = oldSize+i -idx1;
1018 fCont[newindex] = tc->fCont[i];
1019 R__ReleaseMemory(fClass,fKeep->fCont[newindex]);
1020 (*fKeep)[newindex] = (*(tc->fKeep))[i];
1021 tc->fCont[i] = 0;
1022 (*(tc->fKeep))[i] = 0;
1023 }
1024
1025 // cleanup
1026 for (Int_t i = idx2+1; i < tc->GetEntriesFast(); i++) {
1027 tc->fCont[i-(idx2-idx1+1)] = tc->fCont[i];
1028 (*(tc->fKeep))[i-(idx2-idx1+1)] = (*(tc->fKeep))[i];
1029 tc->fCont[i] = 0;
1030 (*(tc->fKeep))[i] = 0;
1031 }
1032 tc->fLast = tc->GetEntriesFast() - 2 - (idx2 - idx1);
1033 fLast = newSize-1;
1034 if (!wasSorted)
1035 Changed();
1036}
1037
1038////////////////////////////////////////////////////////////////////////////////
1039/// Sort multiple TClonesArrays simultaneously with this array.
1040/// If objects in array are sortable (i.e. IsSortable() returns true
1041/// for all objects) then sort array.
1042
1044{
1046 if (nentries <= 1 || fSorted) return;
1047 Bool_t sortedCheck = kTRUE;
1048 for (Int_t i = 0; i < fSize; i++) {
1049 if (fCont[i]) {
1050 if (!fCont[i]->IsSortable()) {
1051 Error("MultiSort", "objects in array are not sortable");
1052 return;
1053 }
1054 }
1055 if (sortedCheck && i > 1) {
1056 if (ObjCompare(fCont[i], fCont[i-1]) < 0) sortedCheck = kFALSE;
1057 }
1058 }
1059 if (sortedCheck) {
1060 fSorted = kTRUE;
1061 return;
1062 }
1063
1064 for (int i = 0; i < nTCs; i++) {
1065 if (tcs[i] == this) {
1066 Error("MultiSort", "tcs[%d] = \"this\"", i);
1067 return;
1068 }
1069 if (tcs[i]->GetEntriesFast() != GetEntriesFast()) {
1070 Error("MultiSort", "tcs[%d] has length %d != length of this (%d)",
1071 i, tcs[i]->GetEntriesFast(), this->GetEntriesFast());
1072 return;
1073 }
1074 }
1075
1076 int nBs = nTCs*2+1;
1077 TObject*** b = new TObject**[nBs];
1078 for (int i = 0; i < nTCs; i++) {
1079 b[2*i] = tcs[i]->fCont;
1080 b[2*i+1] = tcs[i]->fKeep->fCont;
1081 }
1082 b[nBs-1] = fKeep->fCont;
1083 QSort(fCont, nBs, b, 0, TMath::Min(nentries, upto-fLowerBound));
1084 delete [] b;
1085
1086 fLast = -2;
1087 fSorted = kTRUE;
1088}
void Class()
Definition: Class.C:29
SVector< double, 2 > v
Definition: Dict.h:5
#define SafeDelete(p)
Definition: RConfig.hxx:529
#define b(i)
Definition: RSha256.hxx:100
const Ssiz_t kNPOS
Definition: RtypesCore.h:111
int Int_t
Definition: RtypesCore.h:41
short Version_t
Definition: RtypesCore.h:61
int Ssiz_t
Definition: RtypesCore.h:63
unsigned int UInt_t
Definition: RtypesCore.h:42
const Bool_t kFALSE
Definition: RtypesCore.h:88
long Long_t
Definition: RtypesCore.h:50
bool Bool_t
Definition: RtypesCore.h:59
const Bool_t kTRUE
Definition: RtypesCore.h:87
const char Option_t
Definition: RtypesCore.h:62
#define BIT(n)
Definition: Rtypes.h:82
#define ClassImp(name)
Definition: Rtypes.h:363
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:96
int nentries
Definition: THbookFile.cxx:89
R__EXTERN TObjectTable * gObjectTable
Definition: TObjectTable.h:82
typedef void((*Func_t)())
#define snprintf
Definition: civetweb.c:1540
Buffer base class used for serializing objects.
Definition: TBuffer.h:40
@ kCannotHandleMemberWiseStreaming
Definition: TBuffer.h:73
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:75
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition: TClass.cxx:4824
void Destructor(void *obj, Bool_t dtorOnly=kFALSE)
Explicitly call destructor for object.
Definition: TClass.cxx:5181
Int_t Size() const
Return size of object of this class.
Definition: TClass.cxx:5466
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition: TClass.cxx:5700
Int_t GetBaseClassOffset(const TClass *toBase, void *address=0, bool isDerivedObject=true)
Definition: TClass.cxx:2708
Version_t GetClassVersion() const
Definition: TClass.h:391
@ kIsEmulation
Definition: TClass.h:95
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:2885
An array of clone (identical) objects.
Definition: TClonesArray.h:32
virtual void Delete(Option_t *option="")
Clear the clones array.
TObjArray * fKeep
Pointer to the class of the elements.
Definition: TClonesArray.h:36
virtual void Expand(Int_t newSize)
Expand or shrink the array to newSize elements.
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.
virtual void Compress()
Remove empty slots from array.
virtual void SetOwner(Bool_t enable=kTRUE)
A TClonesArray is always the owner of the object it contains.
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 SetClass(const char *classname, Int_t size=1000)
see TClonesArray::SetClass(const TClass*)
virtual void RemoveRange(Int_t idx1, Int_t idx2)
Remove objects from index idx1 to idx2 included.
Bool_t CanBypassStreamer() const
Definition: TClonesArray.h:67
TClass * fClass
Definition: TClonesArray.h:35
TClonesArray & operator=(const TClonesArray &tc)
Assignment operator.
virtual TObject * RemoveAt(Int_t idx)
Remove object at index idx.
virtual void Clear(Option_t *option="")
Clear the clones array.
TObject * ConstructedAt(Int_t idx)
Get an object at index 'idx' that is guaranteed to have been constructed.
virtual TObject * Remove(TObject *obj)
Remove object from array.
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.
virtual void Sort(Int_t upto=kMaxInt)
If objects in array are sortable (i.e.
TObject *& operator[](Int_t idx)
Return pointer to reserved area in which a new object of clones class can be constructed.
TObject * New(Int_t idx)
Create an object of type fClass with the default ctor at the specified index.
void MultiSort(Int_t nTCs, TClonesArray **tcs, Int_t upto=kMaxInt)
Sort multiple TClonesArrays simultaneously with this array.
Bool_t IsSortable() const
Definition: TCollection.h:189
virtual Int_t GrowBy(Int_t delta) const
Increase the collection's capacity by delta slots.
void SetName(const char *name)
Definition: TCollection.h:204
TString fName
Definition: TCollection.h:147
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
Definition: TCollection.h:182
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
An array of TObjects.
Definition: TObjArray.h:37
Int_t IndexOf(const TObject *obj) const
Definition: TObjArray.cxx:589
Int_t GetEntriesFast() const
Definition: TObjArray.h:64
TObject ** fCont
Definition: TObjArray.h:43
virtual void Expand(Int_t newSize)
Expand or shrink the array to newSize elements.
Definition: TObjArray.cxx:386
TObject * Last() const
Return the object in the last filled slot. Returns 0 if no entries.
Definition: TObjArray.cxx:505
Bool_t BoundsOk(const char *where, Int_t at) const
Definition: TObjArray.h:158
virtual void Clear(Option_t *option="")
Remove all objects from the array.
Definition: TObjArray.cxx:320
TObject * UncheckedAt(Int_t i) const
Definition: TObjArray.h:89
TObject * First() const
Return the object in the first slot.
Definition: TObjArray.cxx:495
Int_t fLowerBound
Array contents.
Definition: TObjArray.h:44
Int_t GetAbsLast() const
Return absolute index to last object in array.
Definition: TObjArray.cxx:538
TObjArray(Int_t s=TCollection::kInitCapacity, Int_t lowerBound=0)
Create an object array.
Definition: TObjArray.cxx:63
Int_t fLast
Definition: TObjArray.h:45
void RemoveQuietly(TObject *obj)
Remove an object from the object table.
Mother of all ROOT objects.
Definition: TObject.h:37
virtual void Clear(Option_t *="")
Definition: TObject.h:100
@ kNotDeleted
object has not been deleted
Definition: TObject.h:78
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition: TObject.h:172
virtual TObject * Clone(const char *newname="") const
Make a clone of an object using the Streamer facility.
Definition: TObject.cxx:144
UInt_t fBits
bit field status word
Definition: TObject.h:41
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition: TObject.cxx:694
static Bool_t GetObjectStat()
Get status of object stat flag.
Definition: TObject.cxx:954
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:880
virtual void SetUniqueID(UInt_t uid)
Set the unique object id.
Definition: TObject.cxx:705
virtual Int_t Compare(const TObject *obj) const
Compare abstract method.
Definition: TObject.cxx:159
void MakeZombie()
Definition: TObject.h:49
virtual ~TObject()
TObject destructor.
Definition: TObject.cxx:79
void ResetBit(UInt_t f)
Definition: TObject.h:171
@ kHasUUID
if object has a TUUID (its fUniqueID=UUIDNumber)
Definition: TObject.h:62
@ kIsReferenced
if object is referenced by a TRef or TRefArray
Definition: TObject.h:61
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:328
Basic string class.
Definition: TString.h:131
const char * Data() const
Definition: TString.h:364
const Int_t n
Definition: legend1.C:16
static constexpr double s
Short_t Max(Short_t a, Short_t b)
Definition: TMathBase.h:212
Short_t Min(Short_t a, Short_t b)
Definition: TMathBase.h:180