ROOT  6.07/01
Reference Guide
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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
14 An array of clone (identical) objects. Memory for the objects
15 stored in the array is allocated only once in the lifetime of the
16 clones array. All objects must be of the same class. For the rest
17 this class has the same properties as TObjArray.
18 
19 To reduce the very large number of new and delete calls in large
20 loops 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 ~~~
33 One better uses a TClonesArray which reduces the number of
34 new/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 ~~~
47 To reduce the number of call to the constructor (especially useful
48 if the user class requires memory allocation), the object can be
49 added (and constructed when needed) using ConstructedAt which only
50 calls 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 ~~~
64 Note: the only supported way to add objects to a TClonesArray is
65 via the new with placement method or the ConstructedAt method.
66 The other Add() methods ofTObjArray and its base classes are not
67 allowed.
68 
69 Considering that a new/delete costs about 70 mus on a 300 MHz HP,
70 O(10^9) new/deletes will save about 19 hours.
71 
72 ### NOTE 1
73 
74 C/C++ offers the possibility of allocating and deleting memory.
75 Forgetting to delete allocated memory is a programming error called a
76 "memory leak", i.e. the memory of your process grows and eventually
77 your program crashes. Even if you *always* delete the allocated
78 memory, the recovered space may not be efficiently reused. The
79 process knows that there are portions of free memory, but when you
80 allocate it again, a fresh piece of memory is grabbed. Your program
81 is free from semantic errors, but the total memory of your process
82 still grows, because your program's memory is full of "holes" which
83 reduce the efficiency of memory access; this is called "memory
84 fragmentation". Moreover new / delete are expensive operations in
85 terms of CPU time.
86 
87 Without entering into technical details, TClonesArray allows you to
88 "reuse" the same portion of memory for new/delete avoiding memory
89 fragmentation and memory growth and improving the performance by
90 orders of magnitude. Every time the memory of the TClonesArray has
91 to be reused, the Clear() method is used. To provide its benefits,
92 each TClonesArray must be allocated *once* per process and disposed
93 of (deleted) *only when not needed any more*.
94 
95 So a job should see *only one* deletion for each TClonesArray,
96 which should be Clear()ed during the job several times. Deleting a
97 TClonesArray is a double waste. Not only you do not avoid memory
98 fragmentation, but you worsen it because the TClonesArray itself
99 is a rather heavy structure, and there is quite some code in the
100 destructor, so you have more memory fragmentation and slower code.
101 
102 ### NOTE 2
103 
104 When 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 <stdlib.h>
127 #include "TClonesArray.h"
128 #include "TError.h"
129 #include "TROOT.h"
130 #include "TClass.h"
131 #include "TObjectTable.h"
132 
133 
135 
136 ////////////////////////////////////////////////////////////////////////////////
137 /// Default Constructor.
138 
140 {
141  fClass = 0;
142  fKeep = 0;
143 }
144 
145 ////////////////////////////////////////////////////////////////////////////////
146 /// Create an array of clone objects of classname. The class must inherit from
147 /// TObject. If the class defines its own operator delete(), make sure that
148 /// it looks like this:
149 /// ~~~ {.cpp}
150 /// void MyClass::operator delete(void *vp)
151 /// {
152 /// if ((Long_t) vp != TObject::GetDtorOnly())
153 /// ::operator delete(vp); // delete space
154 /// else
155 /// TObject::SetDtorOnly(0);
156 /// }
157 /// ~~~
158 /// The second argument s indicates an approximate number of objects
159 /// that will be entered in the array. If more than s objects are entered,
160 /// the array will be automatically expanded.
161 ///
162 /// The third argument is not used anymore and only there for backward
163 /// compatibility reasons.
164 
165 TClonesArray::TClonesArray(const char *classname, Int_t s, Bool_t) : TObjArray(s)
166 {
167  fKeep = 0;
168  SetClass(classname,s);
169 }
170 
171 ////////////////////////////////////////////////////////////////////////////////
172 /// Create an array of clone objects of class cl. The class must inherit from
173 /// TObject. If the class defines an own operator delete(), make sure that
174 /// it looks like this:
175 /// ~~~ {.cpp}
176 /// void MyClass::operator delete(void *vp)
177 /// {
178 /// if ((Long_t) vp != TObject::GetDtorOnly())
179 /// ::operator delete(vp); // delete space
180 /// else
181 /// TObject::SetDtorOnly(0);
182 /// }
183 /// ~~~
184 /// The second argument, s, indicates an approximate number of objects
185 /// that will be entered in the array. If more than s objects are entered,
186 /// the array will be automatically expanded.
187 ///
188 /// The third argument is not used anymore and only there for backward
189 /// compatibility reasons.
190 
192 {
193  fKeep = 0;
194  SetClass(cl,s);
195 }
196 
197 ////////////////////////////////////////////////////////////////////////////////
198 /// Copy ctor.
199 
201 {
202  fKeep = new TObjArray(tc.fSize);
203  fClass = tc.fClass;
204 
206 
207  for (Int_t i = 0; i < fSize; i++) {
208  if (tc.fCont[i]) fCont[i] = tc.fCont[i]->Clone();
209  fKeep->fCont[i] = fCont[i];
210  }
211 }
212 
213 ////////////////////////////////////////////////////////////////////////////////
214 /// Assignment operator.
215 
217 {
218  if (this == &tc) return *this;
219 
220  if (fClass != tc.fClass) {
221  Error("operator=", "cannot copy TClonesArray's when classes are different");
222  return *this;
223  }
224 
225  if (tc.fSize > fSize)
227 
228  Int_t i;
229 
230  for (i = 0; i < fSize; i++)
231  if (fKeep->fCont[i]) {
234  ::operator delete(fKeep->fCont[i]);
235  fKeep->fCont[i] = 0;
236  fCont[i] = 0;
237  }
238 
240 
241  for (i = 0; i < tc.fSize; i++) {
242  if (tc.fCont[i]) fKeep->fCont[i] = tc.fCont[i]->Clone();
243  fCont[i] = fKeep->fCont[i];
244  }
245 
246  fLast = tc.fLast;
247  Changed();
248  return *this;
249 }
250 
251 ////////////////////////////////////////////////////////////////////////////////
252 /// Delete a clones array.
253 
255 {
256  if (fKeep) {
257  for (Int_t i = 0; i < fKeep->fSize; i++) {
258  TObject* p = fKeep->fCont[i];
259  if (p && p->TestBit(kNotDeleted)) {
260  // -- The TObject destructor has not been called.
261  fClass->Destructor(p);
262  fKeep->fCont[i] = 0;
263  } else {
264  // -- The TObject destructor was called, just free memory.
265  //
266  // remove any possible entries from the ObjectTable
269  }
270  ::operator delete(p);
271  fKeep->fCont[i] = 0;
272  }
273  }
274  }
275  SafeDelete(fKeep);
276 
277  // Protect against erroneously setting of owner bit
278  SetOwner(kFALSE);
279 }
280 
281 ////////////////////////////////////////////////////////////////////////////////
282 /// When the kBypassStreamer bit is set, the automatically
283 /// generated Streamer can call directly TClass::WriteBuffer.
284 /// Bypassing the Streamer improves the performance when writing/reading
285 /// the objects in the TClonesArray. However there is a drawback:
286 /// When a TClonesArray is written with split=0 bypassing the Streamer,
287 /// the StreamerInfo of the class in the array being optimized,
288 /// one cannot use later the TClonesArray with split>0. For example,
289 /// there is a problem with the following scenario:
290 /// 1. A class Foo has a TClonesArray of Bar objects
291 /// 2. The Foo object is written with split=0 to Tree T1.
292 /// In this case the StreamerInfo for the class Bar is created
293 /// in optimized mode in such a way that data members of the same type
294 /// are written as an array improving the I/O performance.
295 /// 3. In a new program, T1 is read and a new Tree T2 is created
296 /// with the object Foo in split>1
297 /// 4. When the T2 branch is created, the StreamerInfo for the class Bar
298 /// is created with no optimization (mandatory for the split mode).
299 /// The optimized Bar StreamerInfo is going to be used to read
300 /// the TClonesArray in T1. The result will be Bar objects with
301 /// data member values not in the right sequence.
302 /// The solution to this problem is to call BypassStreamer(kFALSE)
303 /// for the TClonesArray. In this case, the normal Bar::Streamer function
304 /// will be called. The Bar::Streamer function works OK independently
305 /// if the Bar StreamerInfo had been generated in optimized mode or not.
306 
308 {
309  if (bypass)
311  else
313 }
314 
315 ////////////////////////////////////////////////////////////////////////////////
316 /// Remove empty slots from array.
317 
319 {
320  Int_t j = 0, je = 0;
321 
322  TObject **tmp = new TObject* [fSize];
323 
324  for (Int_t i = 0; i < fSize; i++) {
325  if (fCont[i]) {
326  fCont[j] = fCont[i];
327  fKeep->fCont[j] = fKeep->fCont[i];
328  j++;
329  } else {
330  tmp[je] = fKeep->fCont[i];
331  je++;
332  }
333  }
334 
335  fLast = j - 1;
336 
337  Int_t jf = 0;
338  for ( ; j < fSize; j++) {
339  fCont[j] = 0;
340  fKeep->fCont[j] = tmp[jf];
341  jf++;
342  }
343 
344  delete [] tmp;
345 
346  R__ASSERT(je == jf);
347 }
348 
349 ////////////////////////////////////////////////////////////////////////////////
350 /// Get an object at index 'idx' that is guaranteed to have been constructed.
351 /// It might be either a freshly allocated object or one that had already been
352 /// allocated (and assumingly used). In the later case, it is the callers
353 /// responsibility to insure that the object is returned to a known state,
354 /// usually by calling the Clear method on the TClonesArray.
355 ///
356 /// Tests to see if the destructor has been called on the object.
357 /// If so, or if the object has never been constructed the class constructor is called using
358 /// New(). If not, return a pointer to the correct memory location.
359 /// This explicitly to deal with TObject classes that allocate memory
360 /// which will be reset (but not deallocated) in their Clear()
361 /// functions.
362 
364 {
365  TObject *obj = (*this)[idx];
366  if ( obj && obj->TestBit(TObject::kNotDeleted) ) {
367  return obj;
368  }
369  return (fClass) ? static_cast<TObject*>(fClass->New(obj)) : 0;
370 }
371 
372 ////////////////////////////////////////////////////////////////////////////////
373 /// Get an object at index 'idx' that is guaranteed to have been constructed.
374 /// It might be either a freshly allocated object or one that had already been
375 /// allocated (and assumingly used). In the later case, the function Clear
376 /// will be called and passed the value of 'clear_options'
377 ///
378 /// Tests to see if the destructor has been called on the object.
379 /// If so, or if the object has never been constructed the class constructor is called using
380 /// New(). If not, return a pointer to the correct memory location.
381 /// This explicitly to deal with TObject classes that allocate memory
382 /// which will be reset (but not deallocated) in their Clear()
383 /// functions.
384 
386 {
387  TObject *obj = (*this)[idx];
388  if ( obj && obj->TestBit(TObject::kNotDeleted) ) {
389  obj->Clear(clear_options);
390  return obj;
391  }
392  return (fClass) ? static_cast<TObject*>(fClass->New(obj)) : 0;
393 }
394 
395 ////////////////////////////////////////////////////////////////////////////////
396 /// Clear the clones array. Only use this routine when your objects don't
397 /// allocate memory since it will not call the object dtors.
398 /// However, if the class in the TClonesArray implements the function
399 /// Clear(Option_t *option) and if option = "C" the function Clear()
400 /// is called for all objects in the array. In the function Clear(), one
401 /// can delete objects or dynamic arrays allocated in the class.
402 /// This procedure is much faster than calling TClonesArray::Delete().
403 /// When the option starts with "C+", eg "C+xyz" the objects in the array
404 /// are in turn cleared with the option "xyz"
405 
407 {
408  if (option && option[0] == 'C') {
409  const char *cplus = strstr(option,"+");
410  if (cplus) {
411  cplus = cplus + 1;
412  } else {
413  cplus = "";
414  }
415  Int_t n = GetEntriesFast();
416  for (Int_t i = 0; i < n; i++) {
417  TObject *obj = UncheckedAt(i);
418  if (obj) {
419  obj->Clear(cplus);
420  obj->ResetBit( kHasUUID );
421  obj->ResetBit( kIsReferenced );
422  obj->SetUniqueID( 0 );
423  }
424  }
425  }
426 
427  // Protect against erroneously setting of owner bit
428  SetOwner(kFALSE);
429 
431 }
432 
433 ////////////////////////////////////////////////////////////////////////////////
434 /// Clear the clones array. Use this routine when your objects allocate
435 /// memory (e.g. objects inheriting from TNamed or containing TStrings
436 /// allocate memory). If not you better use Clear() since if is faster.
437 
439 {
441  // In case of emulated class, we can not use the delete operator
442  // directly, it would use the wrong destructor.
443  for (Int_t i = 0; i < fSize; i++) {
444  if (fCont[i] && fCont[i]->TestBit(kNotDeleted)) {
446  }
447  }
448  } else {
449  Long_t dtoronly = TObject::GetDtorOnly();
450  for (Int_t i = 0; i < fSize; i++) {
451  if (fCont[i] && fCont[i]->TestBit(kNotDeleted)) {
452  // Tell custom operator delete() not to delete space when
453  // object fCont[i] is deleted. Only destructors are called
454  // for this object.
456  delete fCont[i];
457  }
458  }
459  // Restore the state.
460  TObject::SetDtorOnly((void*)dtoronly);
461  }
462 
463  // Protect against erroneously setting of owner bit.
464  SetOwner(kFALSE);
465 
467 }
468 
469 ////////////////////////////////////////////////////////////////////////////////
470 /// Expand or shrink the array to newSize elements.
471 
473 {
474  if (newSize < 0) {
475  Error ("Expand", "newSize must be positive (%d)", newSize);
476  return;
477  }
478  if (newSize == fSize)
479  return;
480  if (newSize < fSize) {
481  // release allocated space in fKeep and set to 0 so
482  // Expand() will shrink correctly
483  for (int i = newSize; i < fSize; i++)
484  if (fKeep->fCont[i]) {
487  ::operator delete(fKeep->fCont[i]);
488  fKeep->fCont[i] = 0;
489  }
490  }
491 
492  TObjArray::Expand(newSize);
493  fKeep->Expand(newSize);
494 }
495 
496 ////////////////////////////////////////////////////////////////////////////////
497 /// Expand or shrink the array to n elements and create the clone
498 /// objects by calling their default ctor. If n is less than the current size
499 /// the array is shrunk and the allocated space is freed.
500 /// This routine is typically used to create a clonesarray into which
501 /// one can directly copy object data without going via the
502 /// "new (arr[i]) MyObj()" (i.e. the vtbl is already set correctly).
503 
505 {
506  if (n < 0) {
507  Error("ExpandCreate", "n must be positive (%d)", n);
508  return ;
509  }
510  if (n > fSize)
512 
513  Int_t i;
514  for (i = 0; i < n; i++) {
515  if (!fKeep->fCont[i]) {
516  fKeep->fCont[i] = (TObject*)fClass->New();
517  } else if (!fKeep->fCont[i]->TestBit(kNotDeleted)) {
518  // The object has been deleted (or never initialized)
519  fClass->New(fKeep->fCont[i]);
520  }
521  fCont[i] = fKeep->fCont[i];
522  }
523 
524  for (i = n; i < fSize; i++)
525  if (fKeep->fCont[i]) {
528  ::operator delete(fKeep->fCont[i]);
529  fKeep->fCont[i] = 0;
530  fCont[i] = 0;
531  }
532 
533  fLast = n - 1;
534  Changed();
535 }
536 
537 ////////////////////////////////////////////////////////////////////////////////
538 /// Expand or shrink the array to n elements and create the clone
539 /// objects by calling their default ctor. If n is less than the current size
540 /// the array is shrunk but the allocated space is _not_ freed.
541 /// This routine is typically used to create a clonesarray into which
542 /// one can directly copy object data without going via the
543 /// "new (arr[i]) MyObj()" (i.e. the vtbl is already set correctly).
544 /// This is a simplified version of ExpandCreate used in the TTree mechanism.
545 
547 {
548  Int_t oldSize = fKeep->GetSize();
549  if (n > fSize)
551 
552  Int_t i;
553  for (i = 0; i < n; i++) {
554  if (i >= oldSize || !fKeep->fCont[i]) {
555  fKeep->fCont[i] = (TObject*)fClass->New();
556  } else if (!fKeep->fCont[i]->TestBit(kNotDeleted)) {
557  // The object has been deleted (or never initialized)
558  fClass->New(fKeep->fCont[i]);
559  }
560  fCont[i] = fKeep->fCont[i];
561  }
562  if (fLast >= n) {
563  memset(fCont + n, 0, (fLast - n + 1) * sizeof(TObject*));
564  }
565  fLast = n - 1;
566  Changed();
567 }
568 
569 ////////////////////////////////////////////////////////////////////////////////
570 /// Remove object at index idx.
571 
573 {
574  if (!BoundsOk("RemoveAt", idx)) return 0;
575 
576  int i = idx-fLowerBound;
577 
578  if (fCont[i] && fCont[i]->TestBit(kNotDeleted)) {
579  // Tell custom operator delete() not to delete space when
580  // object fCont[i] is deleted. Only destructors are called
581  // for this object.
582  Long_t dtoronly = TObject::GetDtorOnly();
584  delete fCont[i];
585  TObject::SetDtorOnly((void*)dtoronly);
586  }
587 
588  if (fCont[i]) {
589  fCont[i] = 0;
590  // recalculate array size
591  if (i == fLast)
592  do { fLast--; } while (fLast >= 0 && fCont[fLast] == 0);
593  Changed();
594  }
595 
596  return 0;
597 }
598 
599 ////////////////////////////////////////////////////////////////////////////////
600 /// Remove object from array.
601 
603 {
604  if (!obj) return 0;
605 
606  Int_t i = IndexOf(obj) - fLowerBound;
607 
608  if (i == -1) return 0;
609 
610  if (fCont[i] && fCont[i]->TestBit(kNotDeleted)) {
611  // Tell custom operator delete() not to delete space when
612  // object fCont[i] is deleted. Only destructors are called
613  // for this object.
614  Long_t dtoronly = TObject::GetDtorOnly();
616  delete fCont[i];
617  TObject::SetDtorOnly((void*)dtoronly);
618  }
619 
620  fCont[i] = 0;
621  // recalculate array size
622  if (i == fLast)
623  do { fLast--; } while (fLast >= 0 && fCont[fLast] == 0);
624  Changed();
625  return obj;
626 }
627 
628 ////////////////////////////////////////////////////////////////////////////////
629 /// Remove objects from index idx1 to idx2 included.
630 
632 {
633  if (!BoundsOk("RemoveRange", idx1)) return;
634  if (!BoundsOk("RemoveRange", idx2)) return;
635 
636  Long_t dtoronly = TObject::GetDtorOnly();
637 
638  idx1 -= fLowerBound;
639  idx2 -= fLowerBound;
640 
641  Bool_t change = kFALSE;
642  for (TObject **obj=fCont+idx1; obj<=fCont+idx2; obj++) {
643  if (!*obj) continue;
644  if ((*obj)->TestBit(kNotDeleted)) {
645  // Tell custom operator delete() not to delete space when
646  // object fCont[i] is deleted. Only destructors are called
647  // for this object.
649  delete *obj;
650  }
651  *obj = 0;
652  change = kTRUE;
653  }
654 
655  TObject::SetDtorOnly((void*)dtoronly);
656 
657  // recalculate array size
658  if (change) Changed();
659  if (idx1 < fLast || fLast > idx2) return;
660  do { fLast--; } while (fLast >= 0 && fCont[fLast] == 0);
661 }
662 
663 ////////////////////////////////////////////////////////////////////////////////
664 /// Create an array of clone objects of class cl. The class must inherit from
665 /// TObject. If the class defines an own operator delete(), make sure that
666 /// it looks like this:
667 /// ~~~ {.cpp}
668 /// void MyClass::operator delete(void *vp)
669 /// {
670 /// if ((Long_t) vp != TObject::GetDtorOnly())
671 /// ::operator delete(vp); // delete space
672 /// else
673 /// TObject::SetDtorOnly(0);
674 /// }
675 /// ~~~
676 /// The second argument s indicates an approximate number of objects
677 /// that will be entered in the array. If more than s objects are entered,
678 /// the array will be automatically expanded.
679 ///
680 /// NB: This function should not be called in the TClonesArray is already
681 /// initialized with a class.
682 
684 {
685  if (fKeep) {
686  Error("SetClass", "TClonesArray already initialized with another class");
687  return;
688  }
689  fClass = (TClass*)cl;
690  if (!fClass) {
691  MakeZombie();
692  Error("SetClass", "called with a null pointer");
693  return;
694  }
695  const char *classname = fClass->GetName();
696  if (!fClass->IsTObject()) {
697  MakeZombie();
698  Error("SetClass", "%s does not inherit from TObject", classname);
699  return;
700  }
702  MakeZombie();
703  Error("SetClass", "%s must inherit from TObject as the left most base class.", classname);
704  return;
705  }
706  Int_t nch = strlen(classname)+2;
707  char *name = new char[nch];
708  snprintf(name,nch, "%ss", classname);
709  SetName(name);
710  delete [] name;
711 
712  fKeep = new TObjArray(s);
713 
715 }
716 
717 ////////////////////////////////////////////////////////////////////////////////
718 ///see TClonesArray::SetClass(const TClass*)
719 
720 void TClonesArray::SetClass(const char *classname, Int_t s)
721 {
722  SetClass(TClass::GetClass(classname),s);
723 }
724 
725 
726 ////////////////////////////////////////////////////////////////////////////////
727 /// A TClonesArray is always the owner of the object it contains.
728 /// However the collection its inherits from (TObjArray) does not.
729 /// Hence this member function needs to be a nop for TClonesArray.
730 
731 void TClonesArray::SetOwner(Bool_t /* enable */)
732 {
733  // Nothing to be done.
734 }
735 
736 ////////////////////////////////////////////////////////////////////////////////
737 /// If objects in array are sortable (i.e. IsSortable() returns true
738 /// for all objects) then sort array.
739 
741 {
742  Int_t nentries = GetAbsLast()+1;
743  if (nentries <= 0 || fSorted) return;
744  for (Int_t i = 0; i < fSize; i++)
745  if (fCont[i]) {
746  if (!fCont[i]->IsSortable()) {
747  Error("Sort", "objects in array are not sortable");
748  return;
749  }
750  }
751 
752  QSort(fCont, fKeep->fCont, 0, TMath::Min(nentries, upto-fLowerBound));
753 
754  fLast = -2;
755  fSorted = kTRUE;
756 }
757 
758 ////////////////////////////////////////////////////////////////////////////////
759 /// Write all objects in array to the I/O buffer. ATTENTION: empty slots
760 /// are also stored (using one byte per slot). If you don't want this
761 /// use a TOrdCollection or TList.
762 
763 void TClonesArray::Streamer(TBuffer &b)
764 {
765  // Important Note: if you modify this function, remember to also modify
766  // TConvertClonesArrayToProxy accordingly
767 
768  Int_t nobjects;
769  char nch;
770  TString s, classv;
771  UInt_t R__s, R__c;
772 
773  if (b.IsReading()) {
774  Version_t v = b.ReadVersion(&R__s, &R__c);
775  if (v == 3) {
776  const Int_t kOldBypassStreamer = BIT(14);
777  if (TestBit(kOldBypassStreamer)) BypassStreamer();
778  }
779  if (v > 2)
780  TObject::Streamer(b);
781  if (v > 1)
782  fName.Streamer(b);
783  s.Streamer(b);
784  classv = s;
785  Int_t clv = 0;
786  Ssiz_t pos = s.Index(";");
787  if (pos != kNPOS) {
788  classv = s(0, pos);
789  s = s(pos+1, s.Length()-pos-1);
790  clv = s.Atoi();
791  }
792  TClass *cl = TClass::GetClass(classv);
793  if (!cl) {
794  printf("TClonesArray::Streamer expecting class %s\n", classv.Data());
795  b.CheckByteCount(R__s, R__c,TClonesArray::IsA());
796  return;
797  }
798 
799  b >> nobjects;
800  if (nobjects < 0)
801  nobjects = -nobjects; // still there for backward compatibility
802  b >> fLowerBound;
803  if (fClass == 0 && fKeep == 0) {
804  fClass = cl;
805  fKeep = new TObjArray(fSize);
806  Expand(nobjects);
807  }
808  if (cl != fClass) {
809  fClass = cl;
810  //this case may happen when switching from an emulated class to the real class
811  //may not be an error. fClass may point to a deleted object
812  //Error("Streamer", "expecting objects of type %s, finding objects"
813  // " of type %s", fClass->GetName(), cl->GetName());
814  //return;
815  }
816 
817  // make sure there are enough slots in the fKeep array
818  if (fKeep->GetSize() < nobjects)
819  Expand(nobjects);
820 
821  //reset fLast. nobjects may be 0
822  Int_t oldLast = fLast;
823  fLast = nobjects-1;
824 
825  //TStreamerInfo *sinfo = fClass->GetStreamerInfo(clv);
827  for (Int_t i = 0; i < nobjects; i++) {
828  if (!fKeep->fCont[i]) {
829  fKeep->fCont[i] = (TObject*)fClass->New();
830  } else if (!fKeep->fCont[i]->TestBit(kNotDeleted)) {
831  // The object has been deleted (or never initialized)
832  fClass->New(fKeep->fCont[i]);
833  }
834 
835  fCont[i] = fKeep->fCont[i];
836  }
837  //sinfo->ReadBufferClones(b,this,nobjects,-1,0);
838  b.ReadClones(this,nobjects,clv);
839 
840  } else {
841  for (Int_t i = 0; i < nobjects; i++) {
842  b >> nch;
843  if (nch) {
844  if (!fKeep->fCont[i])
845  fKeep->fCont[i] = (TObject*)fClass->New();
846  else if (!fKeep->fCont[i]->TestBit(kNotDeleted)) {
847  // The object has been deleted (or never initialized)
848  fClass->New(fKeep->fCont[i]);
849  }
850 
851  fCont[i] = fKeep->fCont[i];
852  b.StreamObject(fKeep->fCont[i]);
853  }
854  }
855  }
856  for (Int_t i = TMath::Max(nobjects,0); i < oldLast+1; ++i) fCont[i] = 0;
857  Changed();
858  b.CheckByteCount(R__s, R__c,TClonesArray::IsA());
859  } else {
860  //Make sure TStreamerInfo is not optimized, otherwise it will not be
861  //possible to support schema evolution in read mode.
862  //In case the StreamerInfo has already been computed and optimized,
863  //one must disable the option BypassStreamer
864  b.ForceWriteInfoClones(this);
865 
866  // make sure the status of bypass streamer is part of the buffer
867  // (bits in TObject), so that when reading the object the right
868  // mode is used, independent of the method (e.g. written via
869  // TMessage, received and stored to a file and then later read via
870  // TBufferFile)
871  Bool_t bypass = kFALSE;
873  bypass = CanBypassStreamer();
875  }
876 
877  R__c = b.WriteVersion(TClonesArray::IsA(), kTRUE);
878  TObject::Streamer(b);
879  fName.Streamer(b);
880  s.Form("%s;%d", fClass->GetName(), fClass->GetClassVersion());
881  s.Streamer(b);
882  nobjects = GetEntriesFast();
883  b << nobjects;
884  b << fLowerBound;
885  if (CanBypassStreamer()) {
886  b.WriteClones(this,nobjects);
887  } else {
888  for (Int_t i = 0; i < nobjects; i++) {
889  if (!fCont[i]) {
890  nch = 0;
891  b << nch;
892  } else {
893  nch = 1;
894  b << nch;
895  b.StreamObject(fCont[i]);
896  }
897  }
898  }
899  b.SetByteCount(R__c, kTRUE);
900 
901  if (bypass)
902  BypassStreamer();
903  }
904 }
905 
906 ////////////////////////////////////////////////////////////////////////////////
907 /// Return pointer to reserved area in which a new object of clones
908 /// class can be constructed. This operator should not be used for
909 /// lefthand side assignments, like a[2] = xxx. Only like,
910 /// new (a[2]) myClass, or xxx = a[2]. Of course right hand side usage
911 /// is only legal after the object has been constructed via the
912 /// new operator or via the New() method. To remove elements from
913 /// the clones array use Remove() or RemoveAt().
914 
916 {
917  if (idx < 0) {
918  Error("operator[]", "out of bounds at %d in %lx", idx, (Long_t)this);
919  return fCont[0];
920  }
921  if (!fClass) {
922  Error("operator[]", "invalid class specified in TClonesArray ctor");
923  return fCont[0];
924  }
925  if (idx >= fSize)
926  Expand(TMath::Max(idx+1, GrowBy(fSize)));
927 
928  if (!fKeep->fCont[idx]) {
930  // Reset the bit so that:
931  // obj = myClonesArray[i];
932  // obj->TestBit(TObject::kNotDeleted)
933  // will behave correctly.
934  // TObject::kNotDeleted is one of the higher bit that is not settable via the public
935  // interface. But luckily we are its friend.
936  fKeep->fCont[idx]->fBits &= ~kNotDeleted;
937  }
938  fCont[idx] = fKeep->fCont[idx];
939 
940  fLast = TMath::Max(idx, GetAbsLast());
941  Changed();
942 
943  return fCont[idx];
944 }
945 
946 ////////////////////////////////////////////////////////////////////////////////
947 /// Return the object at position idx. Returns 0 if idx is out of bounds.
948 
950 {
951  if (idx < 0 || idx >= fSize) {
952  Error("operator[]", "out of bounds at %d in %lx", idx, (Long_t)this);
953  return 0;
954  }
955 
956  return fCont[idx];
957 }
958 
959 ////////////////////////////////////////////////////////////////////////////////
960 /// Create an object of type fClass with the default ctor at the specified
961 /// index. Returns 0 in case of error.
962 
964 {
965  if (idx < 0) {
966  Error("New", "out of bounds at %d in %lx", idx, (Long_t)this);
967  return 0;
968  }
969  if (!fClass) {
970  Error("New", "invalid class specified in TClonesArray ctor");
971  return 0;
972  }
973 
974  return (TObject *)fClass->New(operator[](idx));
975 }
976 
977 //______________________________________________________________________________
978 //
979 // The following functions are utilities implemented by Jason Detwiler
980 // (jadetwiler@lbl.gov)
981 //
982 ////////////////////////////////////////////////////////////////////////////////
983 /// Directly move the object pointers from tc without cloning (copying).
984 /// This TClonesArray takes over ownership of all of tc's object
985 /// pointers. The tc array is left empty upon return.
986 
988 {
989  // tests
990  if (tc == 0 || tc == this || tc->GetEntriesFast() == 0) return;
991  if (fClass != tc->fClass) {
992  Error("AbsorbObjects", "cannot absorb objects when classes are different");
993  return;
994  }
995 
996  // cache the sorted status
997  Bool_t wasSorted = IsSorted() && tc->IsSorted() &&
998  (Last() == 0 || Last()->Compare(tc->First()) == -1);
999 
1000  // expand this
1001  Int_t oldSize = GetEntriesFast();
1002  Int_t newSize = oldSize + tc->GetEntriesFast();
1003  if(newSize > fSize)
1004  Expand(newSize);
1005 
1006  // move
1007  for (Int_t i = 0; i < tc->GetEntriesFast(); ++i) {
1008  fCont[oldSize+i] = tc->fCont[i];
1009  (*fKeep)[oldSize+i] = (*(tc->fKeep))[i];
1010  tc->fCont[i] = 0;
1011  (*(tc->fKeep))[i] = 0;
1012  }
1013 
1014  // cleanup
1015  fLast = newSize-1;
1016  tc->fLast = -1;
1017  if (!wasSorted)
1018  Changed();
1019 }
1020 
1021 ////////////////////////////////////////////////////////////////////////////////
1022 /// Directly move the range of object pointers from tc without cloning
1023 /// (copying).
1024 /// This TClonesArray takes over ownership of all of tc's object pointers
1025 /// from idx1 to idx2. The tc array is re-arranged by return.
1026 
1028 {
1029  // tests
1030  if (tc == 0 || tc == this || tc->GetEntriesFast() == 0) return;
1031  if (fClass != tc->fClass) {
1032  Error("AbsorbObjects", "cannot absorb objects when classes are different");
1033  return;
1034  }
1035 
1036  if (idx1 > idx2) {
1037  Error("AbsorbObjects", "range is not valid: idx1>idx2");
1038  return;
1039  }
1040 
1041  // cache the sorted status
1042  Bool_t wasSorted = IsSorted() && tc->IsSorted() &&
1043  (Last() == 0 || Last()->Compare(tc->First()) == -1);
1044 
1045  // expand this
1046  Int_t oldSize = GetEntriesFast();
1047  Int_t newSize = oldSize + (idx2-idx1+1);
1048  if(newSize > fSize)
1049  Expand(newSize);
1050 
1051  // move
1052  for (Int_t i = idx1; i <= idx2; i++) {
1053  Int_t newindex = oldSize+i -idx1;
1054  fCont[newindex] = tc->fCont[i];
1055  ::operator delete(fKeep->fCont[newindex]);
1056  (*fKeep)[newindex] = (*(tc->fKeep))[i];
1057  tc->fCont[i] = 0;
1058  (*(tc->fKeep))[i] = 0;
1059  }
1060 
1061  // cleanup
1062  for (Int_t i = idx2+1; i < tc->GetEntriesFast(); i++) {
1063  tc->fCont[i-(idx2-idx1+1)] = tc->fCont[i];
1064  (*(tc->fKeep))[i-(idx2-idx1+1)] = (*(tc->fKeep))[i];
1065  tc->fCont[i] = 0;
1066  (*(tc->fKeep))[i] = 0;
1067  }
1068  tc->fLast = tc->GetEntriesFast() - 2 - (idx2 - idx1);
1069  fLast = newSize-1;
1070  if (!wasSorted)
1071  Changed();
1072 }
1073 
1074 ////////////////////////////////////////////////////////////////////////////////
1075 /// Sort multiple TClonesArrays simultaneously with this array.
1076 /// If objects in array are sortable (i.e. IsSortable() returns true
1077 /// for all objects) then sort array.
1078 
1080 {
1081  Int_t nentries = GetAbsLast()+1;
1082  if (nentries <= 1 || fSorted) return;
1083  Bool_t sortedCheck = kTRUE;
1084  for (Int_t i = 0; i < fSize; i++) {
1085  if (fCont[i]) {
1086  if (!fCont[i]->IsSortable()) {
1087  Error("MultiSort", "objects in array are not sortable");
1088  return;
1089  }
1090  }
1091  if (sortedCheck && i > 1) {
1092  if (ObjCompare(fCont[i], fCont[i-1]) < 0) sortedCheck = kFALSE;
1093  }
1094  }
1095  if (sortedCheck) {
1096  fSorted = kTRUE;
1097  return;
1098  }
1099 
1100  for (int i = 0; i < nTCs; i++) {
1101  if (tcs[i] == this) {
1102  Error("MultiSort", "tcs[%d] = \"this\"", i);
1103  return;
1104  }
1105  if (tcs[i]->GetEntriesFast() != GetEntriesFast()) {
1106  Error("MultiSort", "tcs[%d] has length %d != length of this (%d)",
1107  i, tcs[i]->GetEntriesFast(), this->GetEntriesFast());
1108  return;
1109  }
1110  }
1111 
1112  int nBs = nTCs*2+1;
1113  TObject*** b = new TObject**[nBs];
1114  for (int i = 0; i < nTCs; i++) {
1115  b[2*i] = tcs[i]->fCont;
1116  b[2*i+1] = tcs[i]->fKeep->fCont;
1117  }
1118  b[nBs-1] = fKeep->fCont;
1119  QSort(fCont, nBs, b, 0, TMath::Min(nentries, upto-fLowerBound));
1120  delete [] b;
1121 
1122  fLast = -2;
1123  fSorted = kTRUE;
1124 }
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:83
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:298
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:5462
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:42
#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:2625
#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
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()
void Class()
Definition: Class.C:29
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:4602
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:1951
TObject * First() const
Return the object in the first slot.
Definition: TObjArray.cxx:471
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:552
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:4959
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition: TString.cxx:2308
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:381
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:370
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:2801
#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:479
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:508
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:5243
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