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