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