Logo ROOT  
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 Error("Streamer", "expecting class %s but it was not found by TClass::GetClass\n",
763 classv.Data());
764 b.CheckByteCount(R__s, R__c,TClonesArray::IsA());
765 return;
766 }
767
768 b >> nobjects;
769 if (nobjects < 0)
770 nobjects = -nobjects; // still there for backward compatibility
771 b >> fLowerBound;
772 if (fClass == 0) {
773 fClass = cl;
774 if (fKeep == 0) {
775 fKeep = new TObjArray(fSize);
776 Expand(nobjects);
777 }
778 } else if (cl != fClass && classv == fClass->GetName()) {
779 // If fClass' name is different from classv, the user has intentionally changed
780 // the target class, so we must not override it.
781 fClass = cl;
782 //this case may happen when switching from an emulated class to the real class
783 //may not be an error. fClass may point to a deleted object
784 //Error("Streamer", "expecting objects of type %s, finding objects"
785 // " of type %s", fClass->GetName(), cl->GetName());
786 //return;
787 }
788
789 // make sure there are enough slots in the fKeep array
790 if (fKeep->GetSize() < nobjects)
791 Expand(nobjects);
792
793 //reset fLast. nobjects may be 0
794 Int_t oldLast = fLast;
795 fLast = nobjects-1;
796
797 //TStreamerInfo *sinfo = fClass->GetStreamerInfo(clv);
799 for (Int_t i = 0; i < nobjects; i++) {
800 if (!fKeep->fCont[i]) {
801 fKeep->fCont[i] = (TObject*)fClass->New();
802 } else if (!fKeep->fCont[i]->TestBit(kNotDeleted)) {
803 // The object has been deleted (or never initialized)
804 fClass->New(fKeep->fCont[i]);
805 }
806
807 fCont[i] = fKeep->fCont[i];
808 }
809 if (clv < 8 && classv == "TF1") {
810 // To allow backward compatibility of TClonesArray of v5 TF1 objects
811 // that were stored member-wise.
812 TClonesArray temp("ROOT::v5::TF1Data");
813 temp.ExpandCreate(nobjects);
814 b.ReadClones(&temp, nobjects, clv);
815 // And now covert the v5 into the current
817 gClonesArrayTF1Updater(nobjects, temp.GetObjectRef(nullptr), this->GetObjectRef(nullptr));
818 } else if (clv <= 8 && clv > 3 && clv != 6 && classv == "TFormula") {
819 // To allow backwar compatibility of TClonesArray of v5 TF1 objects
820 // that were stored member-wise.
821 TClonesArray temp("ROOT::v5::TFormula");
822 temp.ExpandCreate(nobjects);
823 b.ReadClones(&temp, nobjects, clv);
824 // And now covert the v5 into the current
826 gClonesArrayTFormulaUpdater(nobjects, temp.GetObjectRef(nullptr), this->GetObjectRef(nullptr));
827 } else {
828 // sinfo->ReadBufferClones(b,this,nobjects,-1,0);
829 b.ReadClones(this, nobjects, clv);
830 }
831 } else {
832 for (Int_t i = 0; i < nobjects; i++) {
833 b >> nch;
834 if (nch) {
835 if (!fKeep->fCont[i])
836 fKeep->fCont[i] = (TObject*)fClass->New();
837 else if (!fKeep->fCont[i]->TestBit(kNotDeleted)) {
838 // The object has been deleted (or never initialized)
839 fClass->New(fKeep->fCont[i]);
840 }
841
842 fCont[i] = fKeep->fCont[i];
843 b.StreamObject(fKeep->fCont[i]);
844 }
845 }
846 }
847 for (Int_t i = TMath::Max(nobjects,0); i < oldLast+1; ++i) fCont[i] = 0;
848 Changed();
849 b.CheckByteCount(R__s, R__c,TClonesArray::IsA());
850 } else {
851 //Make sure TStreamerInfo is not optimized, otherwise it will not be
852 //possible to support schema evolution in read mode.
853 //In case the StreamerInfo has already been computed and optimized,
854 //one must disable the option BypassStreamer
855 b.ForceWriteInfoClones(this);
856
857 // make sure the status of bypass streamer is part of the buffer
858 // (bits in TObject), so that when reading the object the right
859 // mode is used, independent of the method (e.g. written via
860 // TMessage, received and stored to a file and then later read via
861 // TBufferFile)
862 Bool_t bypass = kFALSE;
864 bypass = CanBypassStreamer();
866 }
867
868 R__c = b.WriteVersion(TClonesArray::IsA(), kTRUE);
869 TObject::Streamer(b);
870 fName.Streamer(b);
871 s.Form("%s;%d", fClass->GetName(), fClass->GetClassVersion());
872 s.Streamer(b);
873 nobjects = GetEntriesFast();
874 b << nobjects;
875 b << fLowerBound;
876 if (CanBypassStreamer()) {
877 b.WriteClones(this,nobjects);
878 } else {
879 for (Int_t i = 0; i < nobjects; i++) {
880 if (!fCont[i]) {
881 nch = 0;
882 b << nch;
883 } else {
884 nch = 1;
885 b << nch;
886 b.StreamObject(fCont[i]);
887 }
888 }
889 }
890 b.SetByteCount(R__c, kTRUE);
891
892 if (bypass)
894 }
895}
896
897////////////////////////////////////////////////////////////////////////////////
898/// Return pointer to reserved area in which a new object of clones
899/// class can be constructed. This operator should not be used for
900/// lefthand side assignments, like a[2] = xxx. Only like,
901/// new (a[2]) myClass, or xxx = a[2]. Of course right hand side usage
902/// is only legal after the object has been constructed via the
903/// new operator or via the New() method. To remove elements from
904/// the clones array use Remove() or RemoveAt().
905
907{
908 if (idx < 0) {
909 Error("operator[]", "out of bounds at %d in %lx", idx, (Long_t)this);
910 return fCont[0];
911 }
912 if (!fClass) {
913 Error("operator[]", "invalid class specified in TClonesArray ctor");
914 return fCont[0];
915 }
916 if (idx >= fSize)
917 Expand(TMath::Max(idx+1, GrowBy(fSize)));
918
919 if (!fKeep->fCont[idx]) {
921 // Reset the bit so that:
922 // obj = myClonesArray[i];
923 // obj->TestBit(TObject::kNotDeleted)
924 // will behave correctly.
925 // TObject::kNotDeleted is one of the higher bit that is not settable via the public
926 // interface. But luckily we are its friend.
927 fKeep->fCont[idx]->fBits &= ~kNotDeleted;
928 }
929 fCont[idx] = fKeep->fCont[idx];
930
931 fLast = TMath::Max(idx, GetAbsLast());
932 Changed();
933
934 return fCont[idx];
935}
936
937////////////////////////////////////////////////////////////////////////////////
938/// Return the object at position idx. Returns 0 if idx is out of bounds.
939
941{
942 if (idx < 0 || idx >= fSize) {
943 Error("operator[]", "out of bounds at %d in %lx", idx, (Long_t)this);
944 return 0;
945 }
946
947 return fCont[idx];
948}
949
950////////////////////////////////////////////////////////////////////////////////
951/// Create an object of type fClass with the default ctor at the specified
952/// index. Returns 0 in case of error.
953
955{
956 if (idx < 0) {
957 Error("New", "out of bounds at %d in %lx", idx, (Long_t)this);
958 return 0;
959 }
960 if (!fClass) {
961 Error("New", "invalid class specified in TClonesArray ctor");
962 return 0;
963 }
964
965 return (TObject *)fClass->New(operator[](idx));
966}
967
968//______________________________________________________________________________
969//
970// The following functions are utilities implemented by Jason Detwiler
971// (jadetwiler@lbl.gov)
972//
973////////////////////////////////////////////////////////////////////////////////
974/// Directly move the object pointers from tc without cloning (copying).
975/// This TClonesArray takes over ownership of all of tc's object
976/// pointers. The tc array is left empty upon return.
977
979{
980 // tests
981 if (tc == 0 || tc == this || tc->GetEntriesFast() == 0) return;
982 AbsorbObjects(tc, 0, tc->GetEntriesFast() - 1);
983}
984
985////////////////////////////////////////////////////////////////////////////////
986/// Directly move the range of object pointers from tc without cloning
987/// (copying).
988/// This TClonesArray takes over ownership of all of tc's object pointers
989/// from idx1 to idx2. The tc array is re-arranged by return.
990
992{
993 // tests
994 if (tc == 0 || tc == this || tc->GetEntriesFast() == 0) return;
995 if (fClass != tc->fClass) {
996 Error("AbsorbObjects", "cannot absorb objects when classes are different");
997 return;
998 }
999
1000 if (idx1 > idx2) {
1001 Error("AbsorbObjects", "range is not valid: idx1>idx2");
1002 return;
1003 }
1004 if (idx2 >= tc->GetEntriesFast()) {
1005 Error("AbsorbObjects", "range is not valid: idx2 out of bounds");
1006 return;
1007 }
1008
1009 // cache the sorted status
1010 Bool_t wasSorted = IsSorted() && tc->IsSorted() &&
1011 (Last() == 0 || Last()->Compare(tc->First()) == -1);
1012
1013 // expand this
1014 Int_t oldSize = GetEntriesFast();
1015 Int_t newSize = oldSize + (idx2-idx1+1);
1016 if(newSize > fSize)
1017 Expand(newSize);
1018
1019 // move
1020 for (Int_t i = idx1; i <= idx2; i++) {
1021 Int_t newindex = oldSize+i -idx1;
1022 fCont[newindex] = tc->fCont[i];
1023 R__ReleaseMemory(fClass,fKeep->fCont[newindex]);
1024 (*fKeep)[newindex] = (*(tc->fKeep))[i];
1025 tc->fCont[i] = 0;
1026 (*(tc->fKeep))[i] = 0;
1027 }
1028
1029 // cleanup
1030 for (Int_t i = idx2+1; i < tc->GetEntriesFast(); i++) {
1031 tc->fCont[i-(idx2-idx1+1)] = tc->fCont[i];
1032 (*(tc->fKeep))[i-(idx2-idx1+1)] = (*(tc->fKeep))[i];
1033 tc->fCont[i] = 0;
1034 (*(tc->fKeep))[i] = 0;
1035 }
1036 tc->fLast = tc->GetEntriesFast() - 2 - (idx2 - idx1);
1037 fLast = newSize-1;
1038 if (!wasSorted)
1039 Changed();
1040}
1041
1042////////////////////////////////////////////////////////////////////////////////
1043/// Sort multiple TClonesArrays simultaneously with this array.
1044/// If objects in array are sortable (i.e. IsSortable() returns true
1045/// for all objects) then sort array.
1046
1048{
1050 if (nentries <= 1 || fSorted) return;
1051 Bool_t sortedCheck = kTRUE;
1052 for (Int_t i = 0; i < fSize; i++) {
1053 if (fCont[i]) {
1054 if (!fCont[i]->IsSortable()) {
1055 Error("MultiSort", "objects in array are not sortable");
1056 return;
1057 }
1058 }
1059 if (sortedCheck && i > 1) {
1060 if (ObjCompare(fCont[i], fCont[i-1]) < 0) sortedCheck = kFALSE;
1061 }
1062 }
1063 if (sortedCheck) {
1064 fSorted = kTRUE;
1065 return;
1066 }
1067
1068 for (int i = 0; i < nTCs; i++) {
1069 if (tcs[i] == this) {
1070 Error("MultiSort", "tcs[%d] = \"this\"", i);
1071 return;
1072 }
1073 if (tcs[i]->GetEntriesFast() != GetEntriesFast()) {
1074 Error("MultiSort", "tcs[%d] has length %d != length of this (%d)",
1075 i, tcs[i]->GetEntriesFast(), this->GetEntriesFast());
1076 return;
1077 }
1078 }
1079
1080 int nBs = nTCs*2+1;
1081 TObject*** b = new TObject**[nBs];
1082 for (int i = 0; i < nTCs; i++) {
1083 b[2*i] = tcs[i]->fCont;
1084 b[2*i+1] = tcs[i]->fKeep->fCont;
1085 }
1086 b[nBs-1] = fKeep->fCont;
1087 QSort(fCont, nBs, b, 0, TMath::Min(nentries, upto-fLowerBound));
1088 delete [] b;
1089
1090 fLast = -2;
1091 fSorted = kTRUE;
1092}
void Class()
Definition: Class.C:29
#define SafeDelete(p)
Definition: RConfig.hxx:550
#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:83
#define ClassImp(name)
Definition: Rtypes.h:365
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
char name[80]
Definition: TGX11.cxx:109
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:42
@ kCannotHandleMemberWiseStreaming
Definition: TBuffer.h:75
TClass instances represent classes, structs and namespaces in the ROOT type system.
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:4812
void Destructor(void *obj, Bool_t dtorOnly=kFALSE)
Explicitly call destructor for object.
Definition: TClass.cxx:5169
Int_t Size() const
Return size of object of this class.
Definition: TClass.cxx:5454
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition: TClass.cxx:5688
Int_t GetBaseClassOffset(const TClass *toBase, void *address=0, bool isDerivedObject=true)
Definition: TClass.cxx:2729
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:2906
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:604
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:159
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:90
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
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
@ kNotDeleted
object has not been deleted
Definition: TObject.h:78
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