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