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