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