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