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 "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->TestBit(TObject::kNotDeleted)) {
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 = 0;
180 fKeep = 0;
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
194{
195 fKeep = 0;
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 = 0;
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] = 0;
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->TestBit(TObject::kNotDeleted) ) {
370 return obj;
371 }
372 return (fClass) ? static_cast<TObject*>(fClass->New(obj)) : 0;
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->TestBit(TObject::kNotDeleted) ) {
392 obj->Clear(clear_options);
393 return obj;
394 }
395 return (fClass) ? static_cast<TObject*>(fClass->New(obj)) : 0;
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 // In case of emulated class, we can not use the delete operator
445 // directly, it would use the wrong destructor.
446 for (Int_t i = 0; i < fSize; i++) {
447 if (fCont[i] && fCont[i]->TestBit(kNotDeleted)) {
449 }
450 }
451 } else {
452 for (Int_t i = 0; i < fSize; i++) {
453 if (fCont[i] && fCont[i]->TestBit(kNotDeleted)) {
454 fCont[i]->~TObject();
455 }
456 }
457 }
458
459 // Protect against erroneously setting of owner bit.
461
463}
464
465////////////////////////////////////////////////////////////////////////////////
466/// Expand or shrink the array to newSize elements.
467
469{
470 if (newSize < 0) {
471 Error ("Expand", "newSize must be positive (%d)", newSize);
472 return;
473 }
474 if (!fKeep) {
475 Error("ExpandCreate", "Not initialized properly, fKeep is still a nullptr");
476 return;
477 }
478 if (newSize == fSize)
479 return;
480 if (newSize < fSize) {
481 // release allocated space in fKeep and set to 0 so
482 // Expand() will shrink correctly
483 for (int i = newSize; i < fSize; i++)
484 if (fKeep->fCont[i]) {
486 fKeep->fCont[i] = nullptr;
487 }
488 }
489
490 TObjArray::Expand(newSize);
491 fKeep->Expand(newSize);
492}
493
494////////////////////////////////////////////////////////////////////////////////
495/// Expand or shrink the array to n elements and create the clone
496/// objects by calling their default ctor. If n is less than the current size
497/// the array is shrunk and the allocated space is freed.
498/// This routine is typically used to create a clonesarray into which
499/// one can directly copy object data without going via the
500/// "new (arr[i]) MyObj()" (i.e. the vtbl is already set correctly).
501
503{
504 if (n < 0) {
505 Error("ExpandCreate", "n must be positive (%d)", n);
506 return;
507 }
508 if (!fKeep) {
509 Error("ExpandCreate", "Not initialized properly, fKeep is still a nullptr");
510 return;
511 }
512 if (n > fSize)
514
515 Int_t i;
516 for (i = 0; i < n; i++) {
517 if (!fKeep->fCont[i]) {
518 fKeep->fCont[i] = (TObject*)fClass->New();
519 } else if (!fKeep->fCont[i]->TestBit(kNotDeleted)) {
520 // The object has been deleted (or never initialized)
521 fClass->New(fKeep->fCont[i]);
522 }
523 fCont[i] = fKeep->fCont[i];
524 }
525
526 for (i = n; i < fSize; i++)
527 if (fKeep->fCont[i]) {
529 fKeep->fCont[i] = nullptr;
530 fCont[i] = nullptr;
531 }
532
533 fLast = n - 1;
534 Changed();
535}
536
537////////////////////////////////////////////////////////////////////////////////
538/// Expand or shrink the array to n elements and create the clone
539/// objects by calling their default ctor. If n is less than the current size
540/// the array is shrunk but the allocated space is _not_ freed.
541/// This routine is typically used to create a clonesarray into which
542/// one can directly copy object data without going via the
543/// "new (arr[i]) MyObj()" (i.e. the vtbl is already set correctly).
544/// This is a simplified version of ExpandCreate used in the TTree mechanism.
545
547{
548 Int_t oldSize = fKeep->GetSize();
549 if (n > fSize)
551
552 Int_t i;
553 for (i = 0; i < n; i++) {
554 if (i >= oldSize || !fKeep->fCont[i]) {
555 fKeep->fCont[i] = (TObject*)fClass->New();
556 } else if (!fKeep->fCont[i]->TestBit(kNotDeleted)) {
557 // The object has been deleted (or never initialized)
558 fClass->New(fKeep->fCont[i]);
559 }
560 fCont[i] = fKeep->fCont[i];
561 }
562 if (fLast >= n) {
563 memset(fCont + n, 0, (fLast - n + 1) * sizeof(TObject*));
564 }
565 fLast = n - 1;
566 Changed();
567}
568
569////////////////////////////////////////////////////////////////////////////////
570/// Remove object at index idx.
571
573{
574 if (!BoundsOk("RemoveAt", idx)) return 0;
575
576 int i = idx-fLowerBound;
577
578 if (fCont[i] && fCont[i]->TestBit(kNotDeleted)) {
579 fCont[i]->~TObject();
580 }
581
582 if (fCont[i]) {
583 fCont[i] = 0;
584 // recalculate array size
585 if (i == fLast)
586 do { fLast--; } while (fLast >= 0 && fCont[fLast] == 0);
587 Changed();
588 }
589
590 return 0;
591}
592
593////////////////////////////////////////////////////////////////////////////////
594/// Remove object from array.
595
597{
598 if (!obj) return 0;
599
600 Int_t i = IndexOf(obj) - fLowerBound;
601
602 if (i == -1) return 0;
603
604 if (fCont[i] && fCont[i]->TestBit(kNotDeleted)) {
605 fCont[i]->~TObject();
606 }
607
608 fCont[i] = 0;
609 // recalculate array size
610 if (i == fLast)
611 do { fLast--; } while (fLast >= 0 && fCont[fLast] == 0);
612 Changed();
613 return obj;
614}
615
616////////////////////////////////////////////////////////////////////////////////
617/// Remove objects from index idx1 to idx2 included.
618
620{
621 if (!BoundsOk("RemoveRange", idx1)) return;
622 if (!BoundsOk("RemoveRange", idx2)) return;
623
624 idx1 -= fLowerBound;
625 idx2 -= fLowerBound;
626
627 Bool_t change = kFALSE;
628 for (TObject **obj=fCont+idx1; obj<=fCont+idx2; obj++) {
629 if (!*obj) continue;
630 if ((*obj)->TestBit(kNotDeleted)) {
631 (*obj)->~TObject();
632 }
633 *obj = 0;
634 change = kTRUE;
635 }
636
637 // recalculate array size
638 if (change) Changed();
639 if (idx1 < fLast || fLast > idx2) return;
640 do { fLast--; } while (fLast >= 0 && fCont[fLast] == 0);
641}
642
643////////////////////////////////////////////////////////////////////////////////
644/// Create an array of clone objects of class cl. The class must inherit from
645/// TObject.
646/// The second argument s indicates an approximate number of objects
647/// that will be entered in the array. If more than s objects are entered,
648/// the array will be automatically expanded.
649///
650/// NB: This function should not be called in the TClonesArray is already
651/// initialized with a class.
652
654{
655 if (fKeep) {
656 Error("SetClass", "TClonesArray already initialized with another class");
657 return;
658 }
659 fClass = (TClass*)cl;
660 if (!fClass) {
661 MakeZombie();
662 Error("SetClass", "called with a null pointer");
663 return;
664 }
665 const char *classname = fClass->GetName();
666 if (!fClass->IsTObject()) {
667 MakeZombie();
668 Error("SetClass", "%s does not inherit from TObject", classname);
669 return;
670 }
672 MakeZombie();
673 Error("SetClass", "%s must inherit from TObject as the left most base class.", classname);
674 return;
675 }
676 Int_t nch = strlen(classname)+2;
677 char *name = new char[nch];
678 snprintf(name,nch, "%ss", classname);
679 SetName(name);
680 delete [] name;
681
682 fKeep = new TObjArray(s);
683
685}
686
687////////////////////////////////////////////////////////////////////////////////
688///see TClonesArray::SetClass(const TClass*)
689
690void TClonesArray::SetClass(const char *classname, Int_t s)
691{
692 SetClass(TClass::GetClass(classname),s);
693}
694
695
696////////////////////////////////////////////////////////////////////////////////
697/// A TClonesArray is always the owner of the object it contains.
698/// However the collection its inherits from (TObjArray) does not.
699/// Hence this member function needs to be a nop for TClonesArray.
700
702{
703 // Nothing to be done.
704}
705
706////////////////////////////////////////////////////////////////////////////////
707/// If objects in array are sortable (i.e. IsSortable() returns true
708/// for all objects) then sort array.
709
711{
713 if (nentries <= 0 || fSorted) return;
714 for (Int_t i = 0; i < fSize; i++)
715 if (fCont[i]) {
716 if (!fCont[i]->IsSortable()) {
717 Error("Sort", "objects in array are not sortable");
718 return;
719 }
720 }
721
723
724 fLast = -2;
725 fSorted = kTRUE;
726}
727
728////////////////////////////////////////////////////////////////////////////////
729/// Write all objects in array to the I/O buffer. ATTENTION: empty slots
730/// are also stored (using one byte per slot). If you don't want this
731/// use a TOrdCollection or TList.
732
733void TClonesArray::Streamer(TBuffer &b)
734{
735 // Important Note: if you modify this function, remember to also modify
736 // TConvertClonesArrayToProxy accordingly
737
738 Int_t nobjects;
739 char nch;
740 TString s, classv;
741 UInt_t R__s, R__c;
742
743 if (b.IsReading()) {
744 Version_t v = b.ReadVersion(&R__s, &R__c);
745 if (v == 3) {
746 const Int_t kOldBypassStreamer = BIT(14);
747 if (TestBit(kOldBypassStreamer)) BypassStreamer();
748 }
749 if (v > 2)
750 TObject::Streamer(b);
751 if (v > 1)
752 fName.Streamer(b);
753 s.Streamer(b);
754 classv = s;
755 Int_t clv = 0;
756 Ssiz_t pos = s.Index(";");
757 if (pos != kNPOS) {
758 classv = s(0, pos);
759 s = s(pos+1, s.Length()-pos-1);
760 clv = s.Atoi();
761 }
762 TClass *cl = TClass::GetClass(classv);
763 if (!cl) {
764 Error("Streamer", "expecting class %s but it was not found by TClass::GetClass\n",
765 classv.Data());
766 b.CheckByteCount(R__s, R__c,TClonesArray::IsA());
767 return;
768 }
769
770 b >> nobjects;
771 if (nobjects < 0)
772 nobjects = -nobjects; // still there for backward compatibility
773 b >> fLowerBound;
774 if (fClass == 0) {
775 fClass = cl;
776 if (fKeep == 0) {
777 fKeep = new TObjArray(fSize);
778 Expand(nobjects);
779 }
780 } else if (cl != fClass && classv == fClass->GetName()) {
781 // If fClass' name is different from classv, the user has intentionally changed
782 // the target class, so we must not override it.
783 fClass = cl;
784 //this case may happen when switching from an emulated class to the real class
785 //may not be an error. fClass may point to a deleted object
786 //Error("Streamer", "expecting objects of type %s, finding objects"
787 // " of type %s", fClass->GetName(), cl->GetName());
788 //return;
789 }
790
791 // make sure there are enough slots in the fKeep array
792 if (fKeep->GetSize() < nobjects)
793 Expand(nobjects);
794
795 //reset fLast. nobjects may be 0
796 Int_t oldLast = fLast;
797 fLast = nobjects-1;
798
799 //TStreamerInfo *sinfo = fClass->GetStreamerInfo(clv);
801 for (Int_t i = 0; i < nobjects; i++) {
802 if (!fKeep->fCont[i]) {
803 fKeep->fCont[i] = (TObject*)fClass->New();
804 } else if (!fKeep->fCont[i]->TestBit(kNotDeleted)) {
805 // The object has been deleted (or never initialized)
806 fClass->New(fKeep->fCont[i]);
807 }
808
809 fCont[i] = fKeep->fCont[i];
810 }
811 if (clv < 8 && classv == "TF1") {
812 // To allow backward compatibility of TClonesArray of v5 TF1 objects
813 // that were stored member-wise.
814 TClonesArray temp("ROOT::v5::TF1Data");
815 temp.ExpandCreate(nobjects);
816 b.ReadClones(&temp, nobjects, clv);
817 // And now covert the v5 into the current
819 gClonesArrayTF1Updater(nobjects, temp.GetObjectRef(nullptr), this->GetObjectRef(nullptr));
820 } else if (clv <= 8 && clv > 3 && clv != 6 && classv == "TFormula") {
821 // To allow backwar compatibility of TClonesArray of v5 TF1 objects
822 // that were stored member-wise.
823 TClonesArray temp("ROOT::v5::TFormula");
824 temp.ExpandCreate(nobjects);
825 b.ReadClones(&temp, nobjects, clv);
826 // And now covert the v5 into the current
828 gClonesArrayTFormulaUpdater(nobjects, temp.GetObjectRef(nullptr), this->GetObjectRef(nullptr));
829 } else {
830 // sinfo->ReadBufferClones(b,this,nobjects,-1,0);
831 b.ReadClones(this, nobjects, clv);
832 }
833 } else {
834 for (Int_t i = 0; i < nobjects; i++) {
835 b >> nch;
836 if (nch) {
837 if (!fKeep->fCont[i])
838 fKeep->fCont[i] = (TObject*)fClass->New();
839 else if (!fKeep->fCont[i]->TestBit(kNotDeleted)) {
840 // The object has been deleted (or never initialized)
841 fClass->New(fKeep->fCont[i]);
842 }
843
844 fCont[i] = fKeep->fCont[i];
845 b.StreamObject(fKeep->fCont[i]);
846 }
847 }
848 }
849 for (Int_t i = TMath::Max(nobjects,0); i < oldLast+1; ++i) fCont[i] = 0;
850 Changed();
851 b.CheckByteCount(R__s, R__c,TClonesArray::IsA());
852 } else {
853 //Make sure TStreamerInfo is not optimized, otherwise it will not be
854 //possible to support schema evolution in read mode.
855 //In case the StreamerInfo has already been computed and optimized,
856 //one must disable the option BypassStreamer
857 b.ForceWriteInfoClones(this);
858
859 // make sure the status of bypass streamer is part of the buffer
860 // (bits in TObject), so that when reading the object the right
861 // mode is used, independent of the method (e.g. written via
862 // TMessage, received and stored to a file and then later read via
863 // TBufferFile)
864 Bool_t bypass = kFALSE;
866 bypass = CanBypassStreamer();
868 }
869
870 R__c = b.WriteVersion(TClonesArray::IsA(), kTRUE);
871 TObject::Streamer(b);
872 fName.Streamer(b);
873 s.Form("%s;%d", fClass->GetName(), fClass->GetClassVersion());
874 s.Streamer(b);
875 nobjects = GetEntriesFast();
876 b << nobjects;
877 b << fLowerBound;
878 if (CanBypassStreamer()) {
879 b.WriteClones(this,nobjects);
880 } else {
881 for (Int_t i = 0; i < nobjects; i++) {
882 if (!fCont[i]) {
883 nch = 0;
884 b << nch;
885 } else {
886 nch = 1;
887 b << nch;
888 b.StreamObject(fCont[i]);
889 }
890 }
891 }
892 b.SetByteCount(R__c, kTRUE);
893
894 if (bypass)
896 }
897}
898
899////////////////////////////////////////////////////////////////////////////////
900/// Return pointer to reserved area in which a new object of clones
901/// class can be constructed. This operator should not be used for
902/// lefthand side assignments, like a[2] = xxx. Only like,
903/// new (a[2]) myClass, or xxx = a[2]. Of course right hand side usage
904/// is only legal after the object has been constructed via the
905/// new operator or via the New() method. To remove elements from
906/// the clones array use Remove() or RemoveAt().
907
909{
910 if (idx < 0) {
911 Error("operator[]", "out of bounds at %d in %zx", idx, (size_t)this);
912 return fCont[0];
913 }
914 if (!fClass) {
915 Error("operator[]", "invalid class specified in TClonesArray ctor");
916 return fCont[0];
917 }
918 if (idx >= fSize)
919 Expand(TMath::Max(idx+1, GrowBy(fSize)));
920
921 if (!fKeep->fCont[idx]) {
923 // Reset the bit so that:
924 // obj = myClonesArray[i];
925 // obj->TestBit(TObject::kNotDeleted)
926 // will behave correctly.
927 // TObject::kNotDeleted is one of the higher bit that is not settable via the public
928 // interface. But luckily we are its friend.
929 fKeep->fCont[idx]->fBits &= ~kNotDeleted;
930 }
931 fCont[idx] = fKeep->fCont[idx];
932
933 fLast = TMath::Max(idx, GetAbsLast());
934 Changed();
935
936 return fCont[idx];
937}
938
939////////////////////////////////////////////////////////////////////////////////
940/// Return the object at position idx. Returns 0 if idx is out of bounds.
941
943{
944 if (idx < 0 || idx >= fSize) {
945 Error("operator[]", "out of bounds at %d in %zx", idx, (size_t)this);
946 return 0;
947 }
948
949 return fCont[idx];
950}
951
952////////////////////////////////////////////////////////////////////////////////
953/// Create an object of type fClass with the default ctor at the specified
954/// index. Returns 0 in case of error.
955
957{
958 if (idx < 0) {
959 Error("New", "out of bounds at %d in %zx", idx, (size_t)this);
960 return 0;
961 }
962 if (!fClass) {
963 Error("New", "invalid class specified in TClonesArray ctor");
964 return 0;
965 }
966
967 return (TObject *)fClass->New(operator[](idx));
968}
969
970//______________________________________________________________________________
971//
972// The following functions are utilities implemented by Jason Detwiler
973// (jadetwiler@lbl.gov)
974//
975////////////////////////////////////////////////////////////////////////////////
976/// Directly move the object pointers from tc without cloning (copying).
977/// This TClonesArray takes over ownership of all of tc's object
978/// pointers. The tc array is left empty upon return.
979
981{
982 // tests
983 if (tc == 0 || tc == this || tc->GetEntriesFast() == 0) return;
984 AbsorbObjects(tc, 0, tc->GetEntriesFast() - 1);
985}
986
987////////////////////////////////////////////////////////////////////////////////
988/// Directly move the range of object pointers from tc without cloning
989/// (copying).
990/// This TClonesArray takes over ownership of all of tc's object pointers
991/// from idx1 to idx2. The tc array is re-arranged by return.
992
994{
995 // tests
996 if (tc == 0 || tc == this || tc->GetEntriesFast() == 0) return;
997 if (fClass != tc->fClass) {
998 Error("AbsorbObjects", "cannot absorb objects when classes are different");
999 return;
1000 }
1001
1002 if (idx1 > idx2) {
1003 Error("AbsorbObjects", "range is not valid: idx1>idx2");
1004 return;
1005 }
1006 if (idx2 >= tc->GetEntriesFast()) {
1007 Error("AbsorbObjects", "range is not valid: idx2 out of bounds");
1008 return;
1009 }
1010
1011 // cache the sorted status
1012 Bool_t wasSorted = IsSorted() && tc->IsSorted() &&
1013 (Last() == 0 || Last()->Compare(tc->First()) == -1);
1014
1015 // expand this
1016 Int_t oldSize = GetEntriesFast();
1017 Int_t newSize = oldSize + (idx2-idx1+1);
1018 if(newSize > fSize)
1019 Expand(newSize);
1020
1021 // move
1022 for (Int_t i = idx1; i <= idx2; i++) {
1023 Int_t newindex = oldSize+i -idx1;
1024 fCont[newindex] = tc->fCont[i];
1025 R__ReleaseMemory(fClass,fKeep->fCont[newindex]);
1026 (*fKeep)[newindex] = (*(tc->fKeep))[i];
1027 tc->fCont[i] = 0;
1028 (*(tc->fKeep))[i] = 0;
1029 }
1030
1031 // cleanup
1032 for (Int_t i = idx2+1; i < tc->GetEntriesFast(); i++) {
1033 tc->fCont[i-(idx2-idx1+1)] = tc->fCont[i];
1034 (*(tc->fKeep))[i-(idx2-idx1+1)] = (*(tc->fKeep))[i];
1035 tc->fCont[i] = 0;
1036 (*(tc->fKeep))[i] = 0;
1037 }
1038 tc->fLast = tc->GetEntriesFast() - 2 - (idx2 - idx1);
1039 fLast = newSize-1;
1040 if (!wasSorted)
1041 Changed();
1042}
1043
1044////////////////////////////////////////////////////////////////////////////////
1045/// Sort multiple TClonesArrays simultaneously with this array.
1046/// If objects in array are sortable (i.e. IsSortable() returns true
1047/// for all objects) then sort array.
1048
1050{
1052 if (nentries <= 1 || fSorted) return;
1053 Bool_t sortedCheck = kTRUE;
1054 for (Int_t i = 0; i < fSize; i++) {
1055 if (fCont[i]) {
1056 if (!fCont[i]->IsSortable()) {
1057 Error("MultiSort", "objects in array are not sortable");
1058 return;
1059 }
1060 }
1061 if (sortedCheck && i > 1) {
1062 if (ObjCompare(fCont[i], fCont[i-1]) < 0) sortedCheck = kFALSE;
1063 }
1064 }
1065 if (sortedCheck) {
1066 fSorted = kTRUE;
1067 return;
1068 }
1069
1070 for (int i = 0; i < nTCs; i++) {
1071 if (tcs[i] == this) {
1072 Error("MultiSort", "tcs[%d] = \"this\"", i);
1073 return;
1074 }
1075 if (tcs[i]->GetEntriesFast() != GetEntriesFast()) {
1076 Error("MultiSort", "tcs[%d] has length %d != length of this (%d)",
1077 i, tcs[i]->GetEntriesFast(), this->GetEntriesFast());
1078 return;
1079 }
1080 }
1081
1082 int nBs = nTCs*2+1;
1083 TObject*** b = new TObject**[nBs];
1084 for (int i = 0; i < nTCs; i++) {
1085 b[2*i] = tcs[i]->fCont;
1086 b[2*i+1] = tcs[i]->fKeep->fCont;
1087 }
1088 b[nBs-1] = fKeep->fCont;
1089 QSort(fCont, nBs, b, 0, TMath::Min(nentries, upto-fLowerBound));
1090 delete [] b;
1091
1092 fLast = -2;
1093 fSorted = kTRUE;
1094}
void Class()
Definition: Class.C:29
typedef void(GLAPIENTRYP _GLUfuncptr)(void)
#define SafeDelete(p)
Definition: RConfig.hxx:534
#define b(i)
Definition: RSha256.hxx:100
const Ssiz_t kNPOS
Definition: RtypesCore.h:124
int Int_t
Definition: RtypesCore.h:45
short Version_t
Definition: RtypesCore.h:65
int Ssiz_t
Definition: RtypesCore.h:67
unsigned int UInt_t
Definition: RtypesCore.h:46
const Bool_t kFALSE
Definition: RtypesCore.h:101
bool Bool_t
Definition: RtypesCore.h:63
const 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:364
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
char name[80]
Definition: TGX11.cxx:110
int nentries
Definition: THbookFile.cxx:91
R__EXTERN TObjectTable * gObjectTable
Definition: TObjectTable.h:82
#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:80
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition: TClass.cxx:4971
void Destructor(void *obj, Bool_t dtorOnly=kFALSE)
Explicitly call destructor for object.
Definition: TClass.cxx:5393
Int_t Size() const
Return size of object of this class.
Definition: TClass.cxx:5697
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition: TClass.cxx:5931
Int_t GetBaseClassOffset(const TClass *toBase, void *address=0, bool isDerivedObject=true)
Definition: TClass.cxx:2778
Version_t GetClassVersion() const
Definition: TClass.h:417
@ kIsEmulation
Definition: TClass.h:101
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:2955
An array of clone (identical) objects.
Definition: TClonesArray.h:29
virtual void Delete(Option_t *option="")
Clear the clones array.
TObjArray * fKeep
Pointer to the class of the elements.
Definition: TClonesArray.h:33
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:64
TClass * fClass
Definition: TClonesArray.h:32
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:191
virtual Int_t GrowBy(Int_t delta) const
Increase the collection's capacity by delta slots.
void SetName(const char *name)
Definition: TCollection.h:206
TString fName
Definition: TCollection.h:149
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
Definition: TCollection.h:184
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:605
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:387
TObject * Last() const
Return the object in the last filled slot. Returns 0 if no entries.
Definition: TObjArray.cxx:506
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:321
TObject * UncheckedAt(Int_t i) const
Definition: TObjArray.h:90
TObject * First() const
Return the object in the first slot.
Definition: TObjArray.cxx:496
Int_t fLowerBound
Array contents.
Definition: TObjArray.h:44
Int_t GetAbsLast() const
Return absolute index to last object in array.
Definition: TObjArray.cxx:539
TObjArray(Int_t s=TCollection::kInitCapacity, Int_t lowerBound=0)
Create an object array.
Definition: TObjArray.cxx:64
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:115
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition: TObject.h:187
virtual TObject * Clone(const char *newname="") const
Make a clone of an object using the Streamer facility.
Definition: TObject.cxx:146
@ 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:696
static Bool_t GetObjectStat()
Get status of object stat flag.
Definition: TObject.cxx:967
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:893
virtual void SetUniqueID(UInt_t uid)
Set the unique object id.
Definition: TObject.cxx:707
virtual Int_t Compare(const TObject *obj) const
Compare abstract method.
Definition: TObject.cxx:161
void MakeZombie()
Definition: TObject.h:49
virtual ~TObject()
TObject destructor.
Definition: TObject.cxx:81
void ResetBit(UInt_t f)
Definition: TObject.h:186
@ 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:136
const char * Data() const
Definition: TString.h:369
const Int_t n
Definition: legend1.C:16
static constexpr double s
Short_t Max(Short_t a, Short_t b)
Definition: TMathBase.h:208
Short_t Min(Short_t a, Short_t b)
Definition: TMathBase.h:176