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