Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TObjArray.cxx
Go to the documentation of this file.
1 // @(#)root/cont:$Id$
2 // Author: Fons Rademakers 11/09/95
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 TObjArray
13 \ingroup Containers
14 An array of TObjects. The array expands automatically when
15 objects are added (shrinking can be done by hand using Expand(),
16 how nice to have meaningful names -:)).
17 Use operator[] to have "real" array behaviour.
18 
19 Note on ownership and copy:
20 By default the TObjArray does not own the objects it points to and
21 will not delete them unless explicitly asked (via a call to the
22 Delete member function). To assign ownership of the content to
23 the array, call:
24 ~~~ {.cpp}
25  myarr->SetOwner(kTRUE);
26 ~~~
27 When the array owns its content a call to Clear or the deletion of
28 the array itself will lead to the deletion of its contents.
29 
30 You can either make a shallow copy of the array:
31 ~~~ {.cpp}
32  otherarr = new TObjArray(*myarr);
33  *otherarr = *myarr;
34 ~~~
35 in which case ownership (if any) is not transfered but the other
36 array points to the same object as the original array. Note that
37 if the content of either array is deleted the other array is not
38 notified in any way (i.e. still points to the now deleted objects).
39 
40 You can also make a deep copy of the array:
41 ~~~ {.cpp}
42  otherarr = (TObjArray*)myarr->Clone();
43 ~~~
44 in which case the array and the content are both duplicated (i.e.
45 otherarr and myarr do not point to the same objects). If myarr
46 is set to the be the owner of its content, otherarr will also be
47 set to the owner of its own content.
48 */
49 
50 #include "TObjArray.h"
51 #include "TError.h"
52 #include "TROOT.h"
53 #include "TVirtualMutex.h"
54 #include <stdlib.h>
55 
56 ClassImp(TObjArray);
57 
58 ////////////////////////////////////////////////////////////////////////////////
59 /// Create an object array. Using s one can set the array size (default is
60 /// kInitCapacity=16) and lowerBound can be used to set the array lowerbound
61 /// index (default is 0).
62 
63 TObjArray::TObjArray(Int_t s, Int_t lowerBound)
64 {
65  if (s < 0) {
66  Warning("TObjArray", "size (%d) < 0", s);
67  s = TCollection::kInitCapacity;
68  } else if (s == 0)
69  s = TCollection::kInitCapacity;
70  fCont = 0;
71  Init(s, lowerBound);
72 }
73 
74 ////////////////////////////////////////////////////////////////////////////////
75 /// Create a copy of TObjArray a. Note, does not copy the kIsOwner flag.
76 
77 TObjArray::TObjArray(const TObjArray &a) : TSeqCollection()
78 {
79  fCont = 0;
80  Init(a.fSize, a.fLowerBound);
81 
82  for (Int_t i = 0; i < fSize; i++)
83  fCont[i] = a.fCont[i];
84 
85  fLast = a.fLast;
86  fName = a.fName;
87 }
88 
89 ////////////////////////////////////////////////////////////////////////////////
90 /// Delete an array. Objects are not deleted unless the TObjArray is the
91 /// owner (set via SetOwner()).
92 
93 TObjArray::~TObjArray()
94 {
95  if (IsOwner())
96  Delete();
97 
98  TStorage::Dealloc(fCont);
99  fCont = 0;
100  fSize = 0;
101 }
102 
103 ////////////////////////////////////////////////////////////////////////////////
104 /// Assignment operator. Note, unsets the kIsOwner flag.
105 
106 TObjArray& TObjArray::operator=(const TObjArray &a)
107 {
108  if (this != &a) {
109  R__COLLECTION_WRITE_LOCKGUARD(ROOT::gCoreMutex);
110 
111  if (IsOwner())
112  Delete();
113  SetOwner(kFALSE);
114 
115  Init(a.fSize, a.fLowerBound);
116 
117  for (Int_t i = 0; i < fSize; i++)
118  fCont[i] = a.fCont[i];
119 
120  fLast = a.fLast;
121  fName = a.fName;
122  }
123  return *this;
124 }
125 
126 ////////////////////////////////////////////////////////////////////////////////
127 /// Return the object at position i. Returns address at position 0
128 /// if i is out of bounds. Result may be used as an lvalue.
129 
130 TObject *&TObjArray::operator[](Int_t i)
131 {
132  R__COLLECTION_READ_LOCKGUARD(ROOT::gCoreMutex);
133 
134  int j = i-fLowerBound;
135  if (j >= 0 && j < fSize) {
136  fLast = TMath::Max(j, GetAbsLast());
137  Changed();
138  return fCont[j];
139  }
140  BoundsOk("operator[]", i);
141  fLast = -2; // invalidate fLast since the result may be used as an lvalue
142  return fCont[0];
143 }
144 
145 ////////////////////////////////////////////////////////////////////////////////
146 /// Return the object at position at. Returns 0 if i is out of bounds.
147 
148 TObject *TObjArray::operator[](Int_t i) const
149 {
150  R__COLLECTION_READ_LOCKGUARD(ROOT::gCoreMutex);
151 
152  int j = i-fLowerBound;
153  if (j >= 0 && j < fSize) return fCont[j];
154  BoundsOk("operator[] const", i);
155  return 0;
156 }
157 
158 ////////////////////////////////////////////////////////////////////////////////
159 /// Add object in the first slot of the array. This will overwrite the
160 /// first element that might have been there. To have insertion semantics
161 /// use either a TList or a TOrdCollection.
162 
163 void TObjArray::AddFirst(TObject *obj)
164 {
165  R__COLLECTION_WRITE_LOCKGUARD(ROOT::gCoreMutex);
166 
167  fCont[0] = obj;
168  if (fLast == -1)
169  fLast = 0;
170  Changed();
171 }
172 
173 ////////////////////////////////////////////////////////////////////////////////
174 /// Add object in the next empty slot in the array. Expand the array
175 /// if necessary.
176 
177 void TObjArray::AddLast(TObject *obj)
178 {
179  AddAtAndExpand(obj, GetAbsLast()+1+fLowerBound);
180 }
181 
182 ////////////////////////////////////////////////////////////////////////////////
183 /// Add object in the slot before object before. If before=0 add object
184 /// in the first slot. Note that this will overwrite any object that
185 /// might have already been in this slot. For insertion semantics use
186 /// either a TList or a TOrdCollection.
187 
188 void TObjArray::AddBefore(const TObject *before, TObject *obj)
189 {
190  if (!before)
191  AddFirst(obj);
192  else {
193  R__COLLECTION_READ_LOCKGUARD(ROOT::gCoreMutex);
194 
195  Int_t idx = IndexOf(before) - fLowerBound;
196  if (idx == -1) {
197  Error("AddBefore", "before not found, object not added");
198  return;
199  }
200  if (idx == 0) {
201  Error("AddBefore", "cannot add before lowerbound (%d)", fLowerBound);
202  return;
203  }
204  AddAt(obj, idx+fLowerBound-1);
205  }
206 }
207 
208 ////////////////////////////////////////////////////////////////////////////////
209 /// Add object in the slot after object after. If after=0 add object in
210 /// the last empty slot. Note that this will overwrite any object that
211 /// might have already been in this slot. For insertion semantics use
212 /// either a TList or a TOrdCollection.
213 
214 void TObjArray::AddAfter(const TObject *after, TObject *obj)
215 {
216  if (!after)
217  AddLast(obj);
218  else {
219  R__COLLECTION_READ_LOCKGUARD(ROOT::gCoreMutex);
220 
221  Int_t idx = IndexOf(after) - fLowerBound;
222  if (idx == -1) {
223  Error("AddAfter", "after not found, object not added");
224  return;
225  }
226  AddAtAndExpand(obj, idx+fLowerBound+1);
227  }
228 }
229 
230 ////////////////////////////////////////////////////////////////////////////////
231 /// Add object at position idx. If idx is larger than the current size
232 /// of the array, expand the array (double its size).
233 
234 void TObjArray::AddAtAndExpand(TObject *obj, Int_t idx)
235 {
236  R__COLLECTION_WRITE_LOCKGUARD(ROOT::gCoreMutex);
237 
238  if (idx < fLowerBound) {
239  Error("AddAt", "out of bounds at %d in %lx", idx, (Long_t)this);
240  return;
241  }
242  if (idx-fLowerBound >= fSize)
243  Expand(TMath::Max(idx-fLowerBound+1, GrowBy(fSize)));
244  fCont[idx-fLowerBound] = obj;
245  fLast = TMath::Max(idx-fLowerBound, GetAbsLast());
246  Changed();
247 }
248 
249 ////////////////////////////////////////////////////////////////////////////////
250 /// Add object at position ids. Give an error when idx is out of bounds
251 /// (i.e. the array is not expanded).
252 
253 void TObjArray::AddAt(TObject *obj, Int_t idx)
254 {
255  R__COLLECTION_WRITE_LOCKGUARD(ROOT::gCoreMutex);
256 
257  if (!BoundsOk("AddAt", idx)) return;
258 
259  fCont[idx-fLowerBound] = obj;
260  fLast = TMath::Max(idx-fLowerBound, GetAbsLast());
261  Changed();
262 }
263 
264 ////////////////////////////////////////////////////////////////////////////////
265 /// Return the position of the new object.
266 /// Find the first empty cell or AddLast if there is no empty cell
267 
268 Int_t TObjArray::AddAtFree(TObject *obj)
269 {
270  R__COLLECTION_WRITE_LOCKGUARD(ROOT::gCoreMutex);
271 
272  if (Last()) { // <---------- This is to take in account "empty" TObjArray's
273  Int_t i;
274  for (i = 0; i < fSize; i++)
275  if (!fCont[i]) { // Add object at position i
276  fCont[i] = obj;
277  fLast = TMath::Max(i, GetAbsLast());
278  Changed();
279  return i+fLowerBound;
280  }
281  }
282  AddLast(obj);
283  return GetLast();
284 }
285 
286 ////////////////////////////////////////////////////////////////////////////////
287 /// Return the object after obj. Returns 0 if obj is last object.
288 
289 TObject *TObjArray::After(const TObject *obj) const
290 {
291  if (!obj) return 0;
292 
293  R__COLLECTION_READ_LOCKGUARD(ROOT::gCoreMutex);
294 
295  Int_t idx = IndexOf(obj) - fLowerBound;
296  if (idx == -1 || idx == fSize-1) return 0;
297 
298  return fCont[idx+1];
299 }
300 
301 ////////////////////////////////////////////////////////////////////////////////
302 /// Return the object before obj. Returns 0 if obj is first object.
303 
304 TObject *TObjArray::Before(const TObject *obj) const
305 {
306  if (!obj) return 0;
307 
308  R__COLLECTION_READ_LOCKGUARD(ROOT::gCoreMutex);
309 
310  Int_t idx = IndexOf(obj) - fLowerBound;
311  if (idx == -1 || idx == 0) return 0;
312 
313  return fCont[idx-1];
314 }
315 
316 ////////////////////////////////////////////////////////////////////////////////
317 /// Remove all objects from the array. Does not delete the objects
318 /// unless the TObjArray is the owner (set via SetOwner()).
319 
320 void TObjArray::Clear(Option_t *)
321 {
322  R__COLLECTION_WRITE_LOCKGUARD(ROOT::gCoreMutex);
323 
324  if (IsOwner())
325  Delete();
326  else
327  Init(fSize, fLowerBound);
328 }
329 
330 ////////////////////////////////////////////////////////////////////////////////
331 /// Remove empty slots from array.
332 
333 void TObjArray::Compress()
334 {
335  R__COLLECTION_WRITE_LOCKGUARD(ROOT::gCoreMutex);
336 
337  Int_t j = 0;
338 
339  for (Int_t i = 0; i < fSize; i++) {
340  if (fCont[i]) {
341  fCont[j] = fCont[i];
342  j++;
343  }
344  }
345 
346  fLast = j - 1;
347 
348  for ( ; j < fSize; j++)
349  fCont[j] = 0;
350 }
351 
352 ////////////////////////////////////////////////////////////////////////////////
353 /// Remove all objects from the array AND delete all heap based objects.
354 
355 void TObjArray::Delete(Option_t * /* opt */)
356 {
357  // In some case, for example TParallelCoord, a list (the pad's list of
358  // primitives) will contain both the container and the containees
359  // (the TParallelCoordVar) but if the Clear is being called from
360  // the destructor of the container of this list, one of the first
361  // thing done will be the remove the container (the pad) from the
362  // list (of Primitives of the canvas) that was connecting it
363  // (indirectly) to the list of cleanups.
364  // Note: The Code in TParallelCoordVar was changed (circa June 2017),
365  // to no longer have this behavior and thus rely on this code (by moving
366  // from using Draw to Paint) but the structure might still exist elsewhere
367  // so we keep this comment here.
368 
369  R__COLLECTION_WRITE_LOCKGUARD(ROOT::gCoreMutex);
370 
371  // Since we set fCont[i] only after the deletion is completed, we do not
372  // lose the connection and thus do not need to take any special action.
373  for (Int_t i = 0; i < fSize; i++) {
374  if (fCont[i] && fCont[i]->IsOnHeap()) {
375  TCollection::GarbageCollect(fCont[i]);
376  fCont[i] = 0;
377  }
378  }
379 
380  Init(fSize, fLowerBound);
381 }
382 
383 ////////////////////////////////////////////////////////////////////////////////
384 /// Expand or shrink the array to newSize elements.
385 
386 void TObjArray::Expand(Int_t newSize)
387 {
388  R__COLLECTION_WRITE_LOCKGUARD(ROOT::gCoreMutex);
389 
390  if (newSize < 0) {
391  Error ("Expand", "newSize must be positive (%d)", newSize);
392  return;
393  }
394  if (newSize == fSize)
395  return;
396  if (newSize < fSize) {
397  // if the array is shrunk check whether there are nonempty entries
398  for (Int_t j = newSize; j < fSize; j++)
399  if (fCont[j]) {
400  Error ("Expand", "expand would cut off nonempty entries at %d", j);
401  return;
402  }
403  }
404  fCont = (TObject**) TStorage::ReAlloc(fCont, newSize * sizeof(TObject*),
405  fSize * sizeof(TObject*));
406  fSize = newSize;
407 }
408 
409 ////////////////////////////////////////////////////////////////////////////////
410 /// Find an object in this collection using its name. Requires a sequential
411 /// scan till the object has been found. Returns 0 if object with specified
412 /// name is not found.
413 
414 TObject *TObjArray::FindObject(const char *name) const
415 {
416  R__COLLECTION_READ_LOCKGUARD(ROOT::gCoreMutex);
417 
418  Int_t nobjects = GetAbsLast()+1;
419  for (Int_t i = 0; i < nobjects; ++i) {
420  TObject *obj = fCont[i];
421  if (obj && 0==strcmp(name, obj->GetName())) return obj;
422  }
423  return 0;
424 }
425 
426 ////////////////////////////////////////////////////////////////////////////////
427 /// Find an object in this collection using the object's IsEqual()
428 /// member function. Requires a sequential scan till the object has
429 /// been found. Returns 0 if object is not found.
430 /// Typically this function is overridden by a more efficient version
431 /// in concrete collection classes (e.g. THashTable).
432 
433 TObject *TObjArray::FindObject(const TObject *iobj) const
434 {
435  R__COLLECTION_READ_LOCKGUARD(ROOT::gCoreMutex);
436 
437  Int_t nobjects = GetAbsLast()+1;
438  for (Int_t i = 0; i < nobjects; ++i) {
439  TObject *obj = fCont[i];
440  if (obj && obj->IsEqual(iobj)) return obj;
441  }
442  return 0;
443 }
444 
445 ////////////////////////////////////////////////////////////////////////////////
446 /// Stream all objects in the array to or from the I/O buffer.
447 
448 void TObjArray::Streamer(TBuffer &b)
449 {
450  UInt_t R__s, R__c;
451  Int_t nobjects;
452  if (b.IsReading()) {
453  Version_t v = b.ReadVersion(&R__s, &R__c);
454  if (v > 2)
455  TObject::Streamer(b);
456  if (v > 1)
457  fName.Streamer(b);
458 
459  if (GetEntriesFast() > 0) Clear();
460 
461  b >> nobjects;
462  b >> fLowerBound;
463  if (nobjects >= fSize) Expand(nobjects);
464  fLast = -1;
465  TObject *obj;
466  for (Int_t i = 0; i < nobjects; i++) {
467  obj = (TObject*) b.ReadObjectAny(TObject::Class());
468  if (obj) {
469  fCont[i] = obj;
470  fLast = i;
471  }
472  }
473  Changed();
474  b.CheckByteCount(R__s, R__c,TObjArray::IsA());
475  } else {
476  R__COLLECTION_READ_LOCKGUARD(ROOT::gCoreMutex);
477 
478  R__c = b.WriteVersion(TObjArray::IsA(), kTRUE);
479  TObject::Streamer(b);
480  fName.Streamer(b);
481  nobjects = GetAbsLast()+1;
482  b << nobjects;
483  b << fLowerBound;
484 
485  for (Int_t i = 0; i < nobjects; i++) {
486  b << fCont[i];
487  }
488  b.SetByteCount(R__c, kTRUE);
489  }
490 }
491 
492 ////////////////////////////////////////////////////////////////////////////////
493 /// Return the object in the first slot.
494 
495 TObject *TObjArray::First() const
496 {
497  R__COLLECTION_READ_LOCKGUARD(ROOT::gCoreMutex);
498 
499  return fCont[0];
500 }
501 
502 ////////////////////////////////////////////////////////////////////////////////
503 /// Return the object in the last filled slot. Returns 0 if no entries.
504 
505 TObject *TObjArray::Last() const
506 {
507  R__COLLECTION_READ_LOCKGUARD(ROOT::gCoreMutex);
508 
509  if (fLast == -1)
510  return 0;
511  else
512  return fCont[GetAbsLast()];
513 }
514 
515 ////////////////////////////////////////////////////////////////////////////////
516 /// Return the number of objects in array (i.e. number of non-empty slots).
517 /// Attention: use this method ONLY if you want to know the number of
518 /// non-empty slots. This function loops over the complete array and
519 /// is therefore very slow when applied in a loop. Most of the time you
520 /// better use GetEntriesFast() (only in case when there are no empty slots).
521 
522 Int_t TObjArray::GetEntries() const
523 {
524  Int_t cnt = 0;
525 
526  R__COLLECTION_READ_LOCKGUARD(ROOT::gCoreMutex);
527 
528  for (Int_t i = 0; i < fSize; i++)
529  if (fCont[i]) cnt++;
530 
531  return cnt;
532 }
533 
534 ////////////////////////////////////////////////////////////////////////////////
535 /// Return absolute index to last object in array. Returns -1 in case
536 /// array is empty.
537 
538 Int_t TObjArray::GetAbsLast() const
539 {
540  // For efficiency we need sometimes to update fLast so we have
541  // to cast const away. Ugly, but making GetAbsLast() not const breaks
542  // many other const functions.
543 
544  R__COLLECTION_READ_LOCKGUARD(ROOT::gCoreMutex);
545 
546  if (fLast == -2) {
547  for (Int_t i = fSize-1; i >= 0; i--)
548  if (fCont[i]) {
549  R__COLLECTION_WRITE_LOCKGUARD(ROOT::gCoreMutex);
550  ((TObjArray*)this)->fLast = i;
551  return fLast;
552  }
553  R__COLLECTION_WRITE_LOCKGUARD(ROOT::gCoreMutex);
554  ((TObjArray*)this)->fLast = -1;
555  }
556  return fLast;
557 }
558 
559 ////////////////////////////////////////////////////////////////////////////////
560 /// Return the number of objects in array (i.e. number of non-empty slots).
561 /// This is a thread-unsafe version of GetEntriesFast. Use it only if sure
562 /// it will not be invoked concurrently.
563 
564 Int_t TObjArray::GetEntriesUnsafe() const
565 {
566  if (R__unlikely(fLast == -2))
567  return GetEntriesFast();
568  else
569  return fLast + 1;
570 }
571 
572 ////////////////////////////////////////////////////////////////////////////////
573 /// Return index of last object in array. Returns lowerBound-1 in case
574 /// array is empty.
575 
576 Int_t TObjArray::GetLast() const
577 {
578  R__COLLECTION_READ_LOCKGUARD(ROOT::gCoreMutex);
579 
580  return fLowerBound+GetAbsLast();
581 }
582 
583 ////////////////////////////////////////////////////////////////////////////////
584 /// Return address of pointer obj. If obj is 0 returns address of container.
585 
586 TObject **TObjArray::GetObjectRef(const TObject *obj) const
587 {
588  if (!obj)
589  return fCont;
590 
591  R__COLLECTION_READ_LOCKGUARD(ROOT::gCoreMutex);
592 
593  Int_t index = IndexOf(obj);
594  return &fCont[index];
595 }
596 
597 ////////////////////////////////////////////////////////////////////////////////
598 /// - obj != 0 Return index of object in array.
599 /// Returns lowerBound-1 in case array doesn't contain the obj.
600 ///
601 /// - obj == 0 Return the index of the first empty slot.
602 /// Returns lowerBound-1 in case array doesn't contain any empty slot.
603 
604 Int_t TObjArray::IndexOf(const TObject *obj) const
605 {
606  Int_t i;
607 
608  R__COLLECTION_READ_LOCKGUARD(ROOT::gCoreMutex);
609 
610  if (obj) {
611  for (i = 0; i < fSize; i++)
612  if (fCont[i] && fCont[i]->IsEqual(obj))
613  return i+fLowerBound;
614  } else { // Look for the first empty slot
615  for (i = 0; i < fSize; i++)
616  if (!fCont[i])
617  return i+fLowerBound;
618  }
619 
620  return fLowerBound-1;
621 }
622 
623 ////////////////////////////////////////////////////////////////////////////////
624 /// Initialize a TObjArray.
625 
626 void TObjArray::Init(Int_t s, Int_t lowerBound)
627 {
628  R__COLLECTION_WRITE_LOCKGUARD(ROOT::gCoreMutex);
629 
630  if (fCont && fSize != s) {
631  TStorage::Dealloc(fCont);
632  fCont = 0;
633  }
634 
635  fSize = s;
636 
637  if (!fCont)
638  fCont = (TObject**) TStorage::Alloc(fSize*sizeof(TObject*)); //new TObject* [fSize];
639  memset(fCont, 0, fSize*sizeof(TObject*));
640  fLowerBound = lowerBound;
641  fLast = -1;
642  Changed();
643 }
644 
645 ////////////////////////////////////////////////////////////////////////////////
646 /// Returns an array iterator.
647 
648 TIterator *TObjArray::MakeIterator(Bool_t dir) const
649 {
650  R__COLLECTION_READ_LOCKGUARD(ROOT::gCoreMutex);
651  return new TObjArrayIter(this, dir);
652 }
653 
654 ////////////////////////////////////////////////////////////////////////////////
655 /// Generate an out-of-bounds error. Always returns false.
656 
657 Bool_t TObjArray::OutOfBoundsError(const char *where, Int_t i) const
658 {
659  Error(where, "index %d out of bounds (size: %d, this: 0x%lx)", i, fSize, (Long_t)this);
660  return kFALSE;
661 }
662 
663 ////////////////////////////////////////////////////////////////////////////////
664 /// Remove object from this collection and recursively remove the object
665 /// from all other objects (and collections).
666 
667 void TObjArray::RecursiveRemove(TObject *obj)
668 {
669  if (!obj) return;
670 
671  // We need to have the write lock even-though we are 'just'
672  // reading as any insert or remove during the iteration will
673  // invalidate fatally the cursor (e.g. might skip some items)
674  R__COLLECTION_WRITE_LOCKGUARD(ROOT::gCoreMutex);
675 
676  for (int i = 0; i < fSize; i++) {
677  if (fCont[i] && fCont[i]->TestBit(kNotDeleted) && fCont[i]->IsEqual(obj)) {
678  fCont[i] = 0;
679  // recalculate array size
680  if (i == fLast)
681  do {
682  fLast--;
683  } while (fLast >= 0 && fCont[fLast] == 0);
684  Changed();
685  } else if (fCont[i] && fCont[i]->TestBit(kNotDeleted))
686  fCont[i]->RecursiveRemove(obj);
687  }
688 }
689 
690 ////////////////////////////////////////////////////////////////////////////////
691 /// Remove object at index idx.
692 
693 TObject *TObjArray::RemoveAt(Int_t idx)
694 {
695  if (!BoundsOk("RemoveAt", idx)) return 0;
696 
697  R__COLLECTION_WRITE_LOCKGUARD(ROOT::gCoreMutex);
698 
699  int i = idx-fLowerBound;
700 
701  TObject *obj = 0;
702  if (fCont[i]) {
703  obj = fCont[i];
704  fCont[i] = 0;
705  // recalculate array size
706  if (i == fLast)
707  do {
708  fLast--;
709  } while (fLast >= 0 && fCont[fLast] == 0);
710  Changed();
711  }
712  return obj;
713 }
714 
715 ////////////////////////////////////////////////////////////////////////////////
716 /// Remove object from array.
717 
718 TObject *TObjArray::Remove(TObject *obj)
719 {
720  if (!obj) return 0;
721 
722  R__COLLECTION_WRITE_LOCKGUARD(ROOT::gCoreMutex);
723 
724  Int_t idx = IndexOf(obj) - fLowerBound;
725 
726  if (idx == -1) return 0;
727 
728  TObject *ob = fCont[idx];
729  fCont[idx] = 0;
730  // recalculate array size
731  if (idx == fLast)
732  do {
733  fLast--;
734  } while (fLast >= 0 && fCont[fLast] == 0);
735  Changed();
736  return ob;
737 }
738 
739 ////////////////////////////////////////////////////////////////////////////////
740 /// Remove objects from index idx1 to idx2 included.
741 
742 void TObjArray::RemoveRange(Int_t idx1, Int_t idx2)
743 {
744  if (!BoundsOk("RemoveRange", idx1)) return;
745  if (!BoundsOk("RemoveRange", idx2)) return;
746 
747  R__COLLECTION_WRITE_LOCKGUARD(ROOT::gCoreMutex);
748 
749  idx1 -= fLowerBound;
750  idx2 -= fLowerBound;
751 
752  Bool_t change = kFALSE;
753  for (TObject **obj = fCont+idx1; obj <= fCont+idx2; obj++) {
754  if (*obj) {
755  *obj = 0;
756  change = kTRUE;
757  }
758  }
759 
760  // recalculate array size
761  if (change) Changed();
762  if (idx1 < fLast || fLast > idx2) return;
763  do { fLast--; } while (fLast >= 0 && fCont[fLast] == 0);
764 }
765 
766 ////////////////////////////////////////////////////////////////////////////////
767 /// Set index of last object in array, effectively truncating the
768 /// array. Use carefully since whenever last position has to be
769 /// recalculated, e.g. after a Remove() or Sort() it will be reset
770 /// to the last non-empty slot. If last is -2 this will force the
771 /// recalculation of the last used slot.
772 /// If last is -1, this effectively truncate the array completely.
773 
774 void TObjArray::SetLast(Int_t last)
775 {
776  R__COLLECTION_WRITE_LOCKGUARD(ROOT::gCoreMutex);
777 
778  if (last == -2 || last == -1)
779  fLast = last;
780  else if (BoundsOk("SetLast", last))
781  fLast = last - fLowerBound;
782 }
783 
784 ////////////////////////////////////////////////////////////////////////////////
785 /// Randomize objects inside the array, i.e. permute randomly objects.
786 /// With fLast being the index of the last entry in the array, the following
787 /// algorithm is applied to the array:
788 ///
789 /// - for each entry j between 0 and fLast, another entry k is chosen
790 /// randomly between 0 and fLast.
791 /// - the objects at j and k are swapped.
792 /// - this process is repeated ntimes (ntimes = 1 by default).
793 
794 void TObjArray::Randomize(Int_t ntimes)
795 {
796  R__COLLECTION_WRITE_LOCKGUARD(ROOT::gCoreMutex);
797 
798  for (Int_t i = 0; i < ntimes; i++) {
799  for (Int_t j = 0; j < fLast; j++) {
800 #ifdef R__WIN32
801  Int_t k = (Int_t)(0.5+fLast*Double_t(rand())/Double_t((RAND_MAX+1.0)));
802 #else
803  Int_t k = (Int_t)(0.5+fLast*Double_t(random())/Double_t((RAND_MAX+1.0)));
804 #endif
805  if (k == j) continue;
806  TObject *obj = fCont[j];
807  fCont[j] = fCont[k];
808  fCont[k] = obj;
809  }
810  }
811 }
812 
813 ////////////////////////////////////////////////////////////////////////////////
814 /// If objects in array are sortable (i.e. IsSortable() returns true
815 /// for all objects) then sort array.
816 
817 void TObjArray::Sort(Int_t upto)
818 {
819  R__COLLECTION_WRITE_LOCKGUARD(ROOT::gCoreMutex);
820 
821  if (GetAbsLast() == -1 || fSorted) return;
822  for (Int_t i = 0; i < fSize; i++)
823  if (fCont[i]) {
824  if (!fCont[i]->IsSortable()) {
825  Error("Sort", "objects in array are not sortable");
826  return;
827  }
828  }
829 
830  QSort(fCont, 0, TMath::Min(fSize, upto-fLowerBound));
831 
832  fLast = -2;
833  fSorted = kTRUE;
834 }
835 
836 ////////////////////////////////////////////////////////////////////////////////
837 /// Find object using a binary search. Array must first have been sorted.
838 /// Search can be limited by setting upto to desired index.
839 
840 Int_t TObjArray::BinarySearch(TObject *op, Int_t upto)
841 {
842  R__COLLECTION_READ_LOCKGUARD(ROOT::gCoreMutex);
843 
844  Int_t base, position, last, result = 0;
845  TObject *op2;
846 
847  if (!op) return -1;
848 
849  if (!fSorted) {
850  Error("BinarySearch", "array must first be sorted");
851  return -1;
852  }
853 
854  base = 0;
855  last = TMath::Min(fSize, upto-fLowerBound) - 1;
856 
857  while (last >= base) {
858  position = (base+last) / 2;
859  op2 = fCont[position];
860  if (op2 && (result = op->Compare(op2)) == 0)
861  return position + fLowerBound;
862  if (!op2 || result < 0)
863  last = position-1;
864  else
865  base = position+1;
866  }
867  return -1;
868 }
869 
870 /** \class TObjArrayIter
871 Iterator of object array.
872 */
873 
874 ClassImp(TObjArrayIter);
875 
876 ////////////////////////////////////////////////////////////////////////////////
877 /// Create array iterator. By default the iteration direction
878 /// is kIterForward. To go backward use kIterBackward.
879 
880 TObjArrayIter::TObjArrayIter(const TObjArray *arr, Bool_t dir)
881 {
882  fArray = arr;
883  fDirection = dir;
884  Reset();
885 }
886 
887 ////////////////////////////////////////////////////////////////////////////////
888 /// Copy ctor.
889 
890 TObjArrayIter::TObjArrayIter(const TObjArrayIter &iter) : TIterator(iter)
891 {
892  fArray = iter.fArray;
893  fDirection = iter.fDirection;
894  fCursor = iter.fCursor;
895  fCurCursor = iter.fCurCursor;
896 }
897 
898 ////////////////////////////////////////////////////////////////////////////////
899 /// Overridden assignment operator.
900 
901 TIterator &TObjArrayIter::operator=(const TIterator &rhs)
902 {
903  if (this != &rhs && rhs.IsA() == TObjArrayIter::Class()) {
904  const TObjArrayIter &rhs1 = (const TObjArrayIter &)rhs;
905  fArray = rhs1.fArray;
906  fDirection = rhs1.fDirection;
907  fCursor = rhs1.fCursor;
908  fCurCursor = rhs1.fCurCursor;
909  }
910  return *this;
911 }
912 
913 ////////////////////////////////////////////////////////////////////////////////
914 /// Overloaded assignment operator.
915 
916 TObjArrayIter &TObjArrayIter::operator=(const TObjArrayIter &rhs)
917 {
918  if (this != &rhs) {
919  fArray = rhs.fArray;
920  fDirection = rhs.fDirection;
921  fCursor = rhs.fCursor;
922  fCurCursor = rhs.fCurCursor;
923  }
924  return *this;
925 }
926 
927 ////////////////////////////////////////////////////////////////////////////////
928 /// Return next object in array. Returns 0 when no more objects in array.
929 
930 TObject *TObjArrayIter::Next()
931 {
932  if (fDirection == kIterForward) {
933  for ( ; fCursor < fArray->Capacity() && fArray->fCont[fCursor] == 0;
934  fCursor++) { }
935 
936  fCurCursor = fCursor;
937  if (fCursor < fArray->Capacity()) {
938  return fArray->fCont[fCursor++];
939  }
940  } else {
941  for ( ; fCursor >= 0 && fArray->fCont[fCursor] == 0;
942  fCursor--) { }
943 
944  fCurCursor = fCursor;
945  if (fCursor >= 0) {
946  return fArray->fCont[fCursor--];
947  }
948  }
949  return 0;
950 }
951 
952 ////////////////////////////////////////////////////////////////////////////////
953 /// Reset array iterator.
954 
955 void TObjArrayIter::Reset()
956 {
957  if (fDirection == kIterForward)
958  fCursor = 0;
959  else
960  fCursor = fArray->Capacity() - 1;
961 
962  fCurCursor = fCursor;
963 }
964 
965 ////////////////////////////////////////////////////////////////////////////////
966 /// This operator compares two TIterator objects.
967 
968 Bool_t TObjArrayIter::operator!=(const TIterator &aIter) const
969 {
970  if (aIter.IsA() == TObjArrayIter::Class()) {
971  const TObjArrayIter &iter(dynamic_cast<const TObjArrayIter &>(aIter));
972  return (fCurCursor != iter.fCurCursor);
973  }
974  return false; // for base class we don't implement a comparison
975 }
976 
977 ////////////////////////////////////////////////////////////////////////////////
978 /// This operator compares two TObjArrayIter objects.
979 
980 Bool_t TObjArrayIter::operator!=(const TObjArrayIter &aIter) const
981 {
982  return (fCurCursor != aIter.fCurCursor);
983 }
984 
985 ////////////////////////////////////////////////////////////////////////////////
986 /// Return current object or nullptr.
987 
988 TObject *TObjArrayIter::operator*() const
989 {
990  return (((fCurCursor >= 0) && (fCurCursor < fArray->Capacity())) ?
991  fArray->fCont[fCurCursor] : nullptr);
992 }