Logo ROOT   6.12/07
Reference Guide
TList.cxx
Go to the documentation of this file.
1 // @(#)root/cont:$Id$
2 // Author: Fons Rademakers 10/08/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 TList
13 \ingroup Containers
14 A doubly linked list.
15 
16 All classes inheriting from TObject can be
17 inserted in a TList. Before being inserted into the list the object
18 pointer is wrapped in a TObjLink object which contains, besides
19 the object pointer also a previous and next pointer.
20 
21 There are several ways to iterate over a TList; in order of preference, if
22 not forced by other constraints:
23  0. (Preferred way) Using the C++ range-based `for` or `begin()` / `end()`:
24 ~~~ {.cpp}
25  for(const auto&& obj: *GetListOfPrimitives())
26  obj->Write();
27 ~~~
28  1. Using the R__FOR_EACH macro:
29 ~~~ {.cpp}
30  GetListOfPrimitives()->R__FOR_EACH(TObject,Paint)(option);
31 ~~~
32  2. Using the TList iterator TListIter (via the wrapper class TIter):
33 ~~~ {.cpp}
34  TIter next(GetListOfPrimitives());
35  while ((TObject *obj = next()))
36  obj->Draw(next.GetOption());
37 ~~~
38  3. Using the TList iterator TListIter and std::for_each algorithm:
39 ~~~ {.cpp}
40  // A function object, which will be applied to each element
41  // of the given range.
42  struct STestFunctor {
43  bool operator()(TObject *aObj) {
44  ...
45  return true;
46  }
47  }
48  ...
49  ...
50  TIter iter(mylist);
51  for_each( iter.Begin(), TIter::End(), STestFunctor() );
52 ~~~
53  4. Using the TObjLink list entries (that wrap the TObject*):
54 ~~~ {.cpp}
55  TObjLink *lnk = GetListOfPrimitives()->FirstLink();
56  while (lnk) {
57  lnk->GetObject()->Draw(lnk->GetOption());
58  lnk = lnk->Next();
59  }
60 ~~~
61  5. Using the TList's After() and Before() member functions:
62 ~~~ {.cpp}
63  TFree *idcur = this;
64  while (idcur) {
65  ...
66  ...
67  idcur = (TFree*)GetListOfFree()->After(idcur);
68  }
69 ~~~
70 Methods 2, 3 and 4 can also easily iterate backwards using either
71 a backward TIter (using argument kIterBackward) or by using
72 LastLink() and lnk->Prev() or by using the Before() member.
73 */
74 
75 #include "TList.h"
76 #include "TClass.h"
77 #include "TROOT.h"
78 #include "TVirtualMutex.h"
79 
80 #include <string>
81 namespace std {} using namespace std;
82 
84 
85 ////////////////////////////////////////////////////////////////////////////////
86 /// Delete the list. Objects are not deleted unless the TList is the
87 /// owner (set via SetOwner()).
88 
90 {
91  Clear();
92 }
93 
94 ////////////////////////////////////////////////////////////////////////////////
95 /// Add object at the beginning of the list.
96 
98 {
100 
101  if (IsArgNull("AddFirst", obj)) return;
102 
104 
105  if (!fFirst) {
106  fFirst = NewLink(obj);
107  fLast = fFirst;
108  } else {
109  auto t = NewLink(obj);
110  t->fNext = fFirst;
111  fFirst->fPrev = t;
112  fFirst = t;
113  }
114  fSize++;
115  Changed();
116 }
117 
118 ////////////////////////////////////////////////////////////////////////////////
119 /// Add object at the beginning of the list and also store option.
120 /// Storing an option is useful when one wants to change the behaviour
121 /// of an object a little without having to create a complete new
122 /// copy of the object. This feature is used, for example, by the Draw()
123 /// method. It allows the same object to be drawn in different ways.
124 
126 {
128 
129  if (IsArgNull("AddFirst", obj)) return;
130 
132 
133  if (!fFirst) {
134  fFirst = NewOptLink(obj, opt);
135  fLast = fFirst;
136  } else {
137  auto t = NewOptLink(obj, opt);
138  t->fNext = fFirst;
139  fFirst->fPrev = t;
140  fFirst = t;
141  }
142  fSize++;
143  Changed();
144 }
145 
146 ////////////////////////////////////////////////////////////////////////////////
147 /// Add object at the end of the list.
148 
150 {
152 
153  if (IsArgNull("AddLast", obj)) return;
154 
156 
157  if (!fFirst) {
158  fFirst = NewLink(obj);
159  fLast = fFirst;
160  } else
161  fLast = NewLink(obj, fLast);
162  fSize++;
163  Changed();
164 }
165 
166 ////////////////////////////////////////////////////////////////////////////////
167 /// Add object at the end of the list and also store option.
168 /// Storing an option is useful when one wants to change the behaviour
169 /// of an object a little without having to create a complete new
170 /// copy of the object. This feature is used, for example, by the Draw()
171 /// method. It allows the same object to be drawn in different ways.
172 
174 {
176 
177  if (IsArgNull("AddLast", obj)) return;
178 
180 
181  if (!fFirst) {
182  fFirst = NewOptLink(obj, opt);
183  fLast = fFirst;
184  } else
185  fLast = NewOptLink(obj, opt, fLast);
186  fSize++;
187  Changed();
188 }
189 
190 ////////////////////////////////////////////////////////////////////////////////
191 /// Insert object before object before in the list.
192 
193 void TList::AddBefore(const TObject *before, TObject *obj)
194 {
196 
197  if (IsArgNull("AddBefore", obj)) return;
198 
200 
201  if (!before)
202  TList::AddFirst(obj);
203  else {
204  Int_t idx;
205  TObjLink *t = FindLink(before, idx);
206  if (!t) {
207  Error("AddBefore", "before not found, object not added");
208  return;
209  }
210  if (t == fFirst.get())
211  TList::AddFirst(obj);
212  else {
213  NewLink(obj, t->fPrev.lock());
214  fSize++;
215  Changed();
216  }
217  }
218 }
219 
220 ////////////////////////////////////////////////////////////////////////////////
221 /// Insert object before the specified ObjLink object. If before = 0 then add
222 /// to the head of the list. An ObjLink can be obtained by looping over a list
223 /// using the above describe iterator method 3.
224 
225 void TList::AddBefore(TObjLink *before, TObject *obj)
226 {
228 
229  if (IsArgNull("AddBefore", obj)) return;
230 
231  if (!before)
232  TList::AddFirst(obj);
233  else {
234  if (before == fFirst.get())
235  TList::AddFirst(obj);
236  else {
237  NewLink(obj, before->fPrev.lock());
238  fSize++;
239  Changed();
240  }
241  }
242 }
243 
244 ////////////////////////////////////////////////////////////////////////////////
245 /// Insert object after object after in the list.
246 
247 void TList::AddAfter(const TObject *after, TObject *obj)
248 {
250 
251  if (IsArgNull("AddAfter", obj)) return;
252 
254 
255  if (!after)
256  TList::AddLast(obj);
257  else {
258  Int_t idx;
259  TObjLink *t = FindLink(after, idx);
260  if (!t) {
261  Error("AddAfter", "after not found, object not added");
262  return;
263  }
264  if (t == fLast.get())
265  TList::AddLast(obj);
266  else {
267  NewLink(obj, t->shared_from_this());
268  fSize++;
269  Changed();
270  }
271  }
272 }
273 
274 ////////////////////////////////////////////////////////////////////////////////
275 /// Insert object after the specified ObjLink object. If after = 0 then add
276 /// to the tail of the list. An ObjLink can be obtained by looping over a list
277 /// using the above describe iterator method 3.
278 
279 void TList::AddAfter(TObjLink *after, TObject *obj)
280 {
282 
283  if (IsArgNull("AddAfter", obj)) return;
284 
286 
287  if (!after)
288  TList::AddLast(obj);
289  else {
290  if (after == fLast.get())
291  TList::AddLast(obj);
292  else {
293  NewLink(obj, after->shared_from_this());
294  fSize++;
295  Changed();
296  }
297  }
298 }
299 
300 ////////////////////////////////////////////////////////////////////////////////
301 /// Insert object at position idx in the list.
302 
303 void TList::AddAt(TObject *obj, Int_t idx)
304 {
306 
307  if (IsArgNull("AddAt", obj)) return;
308 
310 
311  TObjLink *lnk = LinkAt(idx);
312  if (!lnk)
313  TList::AddLast(obj);
314  else if (lnk == fFirst.get())
315  TList::AddFirst(obj);
316  else {
317  NewLink(obj, lnk->fPrev.lock());
318  fSize++;
319  Changed();
320  }
321 }
322 
323 ////////////////////////////////////////////////////////////////////////////////
324 /// Returns the object after object obj. Obj is found using the
325 /// object's IsEqual() method. Returns 0 if obj is last in list.
326 
327 TObject *TList::After(const TObject *obj) const
328 {
330 
331  TObjLink *t;
332 
334 
335  auto cached = fCache.lock();
336  if (cached.get() && cached->GetObject() && cached->GetObject()->IsEqual(obj)) {
337  t = cached.get();
338  ((TList*)this)->fCache = cached->fNext; //cast const away, fCache should be mutable
339  } else {
340  Int_t idx;
341  t = FindLink(obj, idx);
342  if (t) ((TList*)this)->fCache = t->fNext;
343  }
344 
345  if (t && t->Next())
346  return t->Next()->GetObject();
347  else
348  return 0;
349 }
350 
351 ////////////////////////////////////////////////////////////////////////////////
352 /// Returns the object at position idx. Returns 0 if idx is out of range.
353 
355 {
358 
359  TObjLink *lnk = LinkAt(idx);
360  if (lnk) return lnk->GetObject();
361  return 0;
362 }
363 
364 ////////////////////////////////////////////////////////////////////////////////
365 /// Returns the object before object obj. Obj is found using the
366 /// object's IsEqual() method. Returns 0 if obj is first in list.
367 
368 TObject *TList::Before(const TObject *obj) const
369 {
372 
373  TObjLink *t;
374 
375  auto cached = fCache.lock();
376  if (cached.get() && cached->GetObject() && cached->GetObject()->IsEqual(obj)) {
377  t = cached.get();
378  ((TList*)this)->fCache = cached->fPrev; //cast const away, fCache should be mutable
379  } else {
380  Int_t idx;
381  t = FindLink(obj, idx);
382  if (t) ((TList*)this)->fCache = t->fPrev;
383  }
384 
385  if (t && t->Prev())
386  return t->Prev()->GetObject();
387  else
388  return 0;
389 }
390 
391 ////////////////////////////////////////////////////////////////////////////////
392 /// Remove all objects from the list. Does not delete the objects
393 /// unless the TList is the owner (set via SetOwner()) and option
394 /// "nodelete" is not set.
395 /// If option="nodelete" then don't delete any heap objects that were
396 /// marked with the kCanDelete bit, otherwise these objects will be
397 /// deleted (this option is used by THashTable::Clear()).
398 
399 void TList::Clear(Option_t *option)
400 {
403 
404  Bool_t nodel = option ? (!strcmp(option, "nodelete") ? kTRUE : kFALSE) : kFALSE;
405 
406  if (!nodel && IsOwner()) {
407  Delete(option);
408  return;
409  }
410 
411  // In some case, for example TParallelCoord, a list (the pad's list of
412  // primitives) will contain both the container and the containees
413  // (the TParallelCoordVar) but if the Clear is being called from
414  // the destructor of the container of this list, one of the first
415  // thing done will be the remove the container (the pad) for the
416  // list (of Primitives of the canvas) that was connecting it
417  // (indirectly) to the list of cleanups.
418  // Note: The Code in TParallelCoordVar was changed (circa June 2017),
419  // to no longer have this behavior and thus rely on this code (by moving
420  // from using Draw to Paint) but the structure might still exist elsewhere
421  // so we keep this comment here.
422 
423  // To preserve this connection (without introducing one when there was none),
424  // we re-use fCache to inform RecursiveRemove of the node currently
425  // being cleared/deleted.
426  while (fFirst) {
427  auto tlk = fFirst;
428  fFirst = fFirst->fNext;
429  fSize--;
430 
431 
432  // Make node available to RecursiveRemove
433  tlk->fNext.reset();
434  tlk->fPrev.reset();
435  fCache = tlk;
436 
437  // delete only heap objects marked OK to clear
438  auto obj = tlk->GetObject();
439  if (!nodel && obj) {
440  if (!obj->TestBit(kNotDeleted)) {
441  Error("Clear", "A list is accessing an object (%p) already deleted (list name = %s)",
442  obj, GetName());
443  } else if (obj->IsOnHeap()) {
444  if (obj->TestBit(kCanDelete)) {
445  if (obj->TestBit(kNotDeleted)) {
447  }
448  }
449  }
450  }
451  // delete tlk;
452  }
453  fFirst.reset();
454  fLast.reset();
455  fCache.reset();
456  fSize = 0;
457  Changed();
458 }
459 
460 ////////////////////////////////////////////////////////////////////////////////
461 /// Remove all objects from the list AND delete all heap based objects.
462 /// If option="slow" then keep list consistent during delete. This allows
463 /// recursive list operations during the delete (e.g. during the dtor
464 /// of an object in this list one can still access the list to search for
465 /// other not yet deleted objects).
466 
467 void TList::Delete(Option_t *option)
468 {
471 
472  Bool_t slow = option ? (!strcmp(option, "slow") ? kTRUE : kFALSE) : kFALSE;
473 
474  TList removeDirectory; // need to deregister these from their directory
475 
476  if (slow) {
477 
478  // In some case, for example TParallelCoord, a list (the pad's list of
479  // primitives) will contain both the container and the containees
480  // (the TParallelCoorVar) but if the Clear is being called from
481  // the destructor of the container of this list, one of the first
482  // thing done will be the remove the container (the pad) for the
483  // list (of Primitives of the canvas) that was connecting it
484  // (indirectly) to the list of cleanups.
485 
486  // To preserve this connection (without introducing one when there was none),
487  // we re-use fCache to inform RecursiveRemove of the node currently
488  // being cleared/deleted.
489  while (fFirst) {
490  auto tlk = fFirst;
491  fFirst = fFirst->fNext;
492  fSize--;
493 
494  // Make node available to RecursiveRemove
495  tlk->fNext.reset();
496  tlk->fPrev.reset();
497  fCache = tlk;
498 
499  // delete only heap objects
500  auto obj = tlk->GetObject();
501  if (obj && !obj->TestBit(kNotDeleted))
502  Error("Delete", "A list is accessing an object (%p) already deleted (list name = %s)",
503  obj, GetName());
504  else if (obj && obj->IsOnHeap())
506  else if (obj && obj->IsA()->GetDirectoryAutoAdd())
507  removeDirectory.Add(obj);
508 
509  // delete tlk;
510  }
511 
512  fFirst.reset();
513  fLast.reset();
514  fCache.reset();
515  fSize = 0;
516 
517  } else {
518 
519  auto first = fFirst; //pointer to first entry in linked list
520  fFirst.reset();
521  fLast.reset();
522  fCache.reset();
523  fSize = 0;
524  while (first) {
525  auto tlk = first;
526  first = first->fNext;
527  // delete only heap objects
528  auto obj = tlk->GetObject();
529  tlk->SetObject(nullptr);
530  if (obj && !obj->TestBit(kNotDeleted))
531  Error("Delete", "A list is accessing an object (%p) already deleted (list name = %s)",
532  obj, GetName());
533  else if (obj && obj->IsOnHeap())
535  else if (obj && obj->IsA()->GetDirectoryAutoAdd())
536  removeDirectory.Add(obj);
537 
538  // The formerly first token, when tlk goes out of scope has no more references
539  // because of the fFirst.reset()
540  }
541  }
542 
543  // These objects cannot expect to have a valid TDirectory anymore;
544  // e.g. because *this is the TDirectory's list of objects. Even if
545  // not, they are supposed to be deleted, so we can as well unregister
546  // them from their directory, even if they are stack-based:
547  TIter iRemDir(&removeDirectory);
548  TObject* dirRem = 0;
549  while ((dirRem = iRemDir())) {
550  (*dirRem->IsA()->GetDirectoryAutoAdd())(dirRem, 0);
551  }
552  Changed();
553 }
554 
555 ////////////////////////////////////////////////////////////////////////////////
556 /// Delete a TObjLink object.
557 #if 0
558 void TList::DeleteLink(TObjLink *lnk)
559 {
561 
562  lnk->fNext = lnk->fPrev = 0;
563  lnk->fObject = 0;
564  delete lnk;
565 }
566 #endif
567 
568 ////////////////////////////////////////////////////////////////////////////////
569 /// Find an object in this list using its name. Requires a sequential
570 /// scan till the object has been found. Returns 0 if object with specified
571 /// name is not found. This method overrides the generic FindObject()
572 /// of TCollection for efficiency reasons.
573 
574 TObject *TList::FindObject(const char *name) const
575 {
577 
578  if (!name)
579  return nullptr;
580 
582 
583  for (TObjLink *lnk = FirstLink(); lnk != nullptr; lnk = lnk->Next()) {
584  if (TObject *obj = lnk->GetObject()) {
585  const char *objname = obj->GetName();
586  if (objname && strcmp(name, objname) == 0)
587  return obj;
588  }
589  }
590 
591  return nullptr;
592 }
593 
594 ////////////////////////////////////////////////////////////////////////////////
595 /// Find an object in this list using the object's IsEqual()
596 /// member function. Requires a sequential scan till the object has
597 /// been found. Returns 0 if object is not found.
598 /// This method overrides the generic FindObject() of TCollection for
599 /// efficiency reasons.
600 
602 {
604 
605  if (!obj)
606  return nullptr;
607 
609 
610  TObjLink *lnk = FirstLink();
611 
612  while (lnk) {
613  TObject *ob = lnk->GetObject();
614  if (ob->IsEqual(obj)) return ob;
615  lnk = lnk->Next();
616  }
617  return nullptr;
618 }
619 
620 ////////////////////////////////////////////////////////////////////////////////
621 /// Returns the TObjLink object that contains object obj. In idx it returns
622 /// the position of the object in the list.
623 
624 TObjLink *TList::FindLink(const TObject *obj, Int_t &idx) const
625 {
627 
628  if (!obj)
629  return nullptr;
630 
632 
633  if (!fFirst) return 0;
634 
635  TObject *object;
636  TObjLink *lnk = fFirst.get();
637  idx = 0;
638 
639  while (lnk) {
640  object = lnk->GetObject();
641  if (object) {
642  if (object->TestBit(kNotDeleted)) {
643  if (object->IsEqual(obj)) return lnk;
644  }
645  }
646  lnk = lnk->Next();
647  idx++;
648  }
649  return 0;
650 }
651 
652 ////////////////////////////////////////////////////////////////////////////////
653 /// Return the first object in the list. Returns 0 when list is empty.
654 
656 {
659 
660  if (fFirst) return fFirst->GetObject();
661  return 0;
662 }
663 
664 ////////////////////////////////////////////////////////////////////////////////
665 /// Return address of pointer to obj
666 
668 {
670 
671  if (!obj)
672  return nullptr;
673 
675 
676  TObjLink *lnk = FirstLink();
677 
678  while (lnk) {
679  TObject *ob = lnk->GetObject();
680  if (ob->IsEqual(obj)) return lnk->GetObjectRef();
681  lnk = lnk->Next();
682  }
683  return 0;
684 }
685 
686 ////////////////////////////////////////////////////////////////////////////////
687 /// Return the last object in the list. Returns 0 when list is empty.
688 
690 {
693 
694  if (fLast) return fLast->GetObject();
695  return 0;
696 }
697 
698 ////////////////////////////////////////////////////////////////////////////////
699 /// Return the TObjLink object at index idx.
700 
702 {
705 
706  Int_t i = 0;
707  TObjLink *lnk = fFirst.get();
708  while (i < idx && lnk) {
709  i++;
710  lnk = lnk->Next();
711  }
712  return lnk;
713 }
714 
715 ////////////////////////////////////////////////////////////////////////////////
716 /// Return a list iterator.
717 
719 {
722 
723  return new TListIter(this, dir);
724 }
725 
726 ////////////////////////////////////////////////////////////////////////////////
727 /// Return a new TObjLink.
728 
730 {
733 
734  auto newlink = std::make_shared<TObjLink>(obj);
735  if (prev) {
736  InsertAfter(newlink, prev);
737  }
738  return newlink;
739 }
740 
741 ////////////////////////////////////////////////////////////////////////////////
742 /// Return a new TObjOptLink (a TObjLink that also stores the option).
743 
745 {
748 
749  auto newlink = std::make_shared<TObjOptLink>(obj, opt);
750  if (prev) {
751  InsertAfter(newlink, prev);
752  }
753  return newlink;
754 }
755 
756 ////////////////////////////////////////////////////////////////////////////////
757 /// Remove object from this collection and recursively remove the object
758 /// from all other objects (and collections).
759 
761 {
763 
764  if (!obj) return;
765 
766  // When fCache is set and has no previous and next node, it represents
767  // the node being cleared and/or deleted.
768  {
769  auto cached = fCache.lock();
770  if (cached && cached->fNext.get() == nullptr && cached->fPrev.lock().get() == nullptr) {
771  TObject *ob = cached->GetObject();
772  if (ob && ob->TestBit(kNotDeleted)) {
773  ob->RecursiveRemove(obj);
774  }
775  }
776  }
777 
778  if (!fFirst.get())
779  return;
780 
781  auto lnk = fFirst;
782  decltype(lnk) next;
783  while (lnk.get()) {
784  next = lnk->fNext;
785  TObject *ob = lnk->GetObject();
786  if (ob && ob->TestBit(kNotDeleted)) {
787  if (ob->IsEqual(obj)) {
788  lnk->SetObject(nullptr);
789  if (lnk == fFirst) {
790  fFirst = next;
791  if (lnk == fLast)
792  fLast = fFirst;
793  else
794  fFirst->fPrev.reset();
795  // DeleteLink(lnk);
796  } else if (lnk == fLast) {
797  fLast = lnk->fPrev.lock();
798  fLast->fNext.reset();
799  // DeleteLink(lnk);
800  } else {
801  lnk->Prev()->fNext = next;
802  lnk->Next()->fPrev = lnk->fPrev;
803  // DeleteLink(lnk);
804  }
805  fSize--;
806  fCache.reset();
807  Changed();
808  } else
809  ob->RecursiveRemove(obj);
810  }
811  lnk = next;
812  }
813 }
814 
815 ////////////////////////////////////////////////////////////////////////////////
816 /// Remove object from the list.
817 
819 {
821 
822  if (!obj) return 0;
823 
824  Int_t idx;
825  TObjLink *lnk = FindLink(obj, idx);
826 
827  if (!lnk) return 0;
828 
829  // return object found, which may be (pointer wise) different than the
830  // input object (depending on what IsEqual() is doing)
831 
833 
834  TObject *ob = lnk->GetObject();
835  lnk->SetObject(nullptr);
836  if (lnk == fFirst.get()) {
837  fFirst = lnk->fNext;
838  // lnk is still alive as we have either fLast
839  // or the 'new' fFirst->fPrev pointing to it.
840  if (lnk == fLast.get()) {
841  fLast.reset();
842  fFirst.reset();
843  } else
844  fFirst->fPrev.reset();
845  //DeleteLink(lnk);
846  } else if (lnk == fLast.get()) {
847  fLast = lnk->fPrev.lock();
848  fLast->fNext.reset();
849  //DeleteLink(lnk);
850  } else {
851  lnk->Next()->fPrev = lnk->fPrev;
852  lnk->Prev()->fNext = lnk->fNext;
853  //DeleteLink(lnk);
854  }
855  fSize--;
856  fCache.reset();
857  Changed();
858 
859  return ob;
860 }
861 
862 ////////////////////////////////////////////////////////////////////////////////
863 /// Remove object link (and therefore the object it contains)
864 /// from the list.
865 
867 {
869 
870  if (!lnk) return 0;
871 
873 
874  TObject *obj = lnk->GetObject();
875  lnk->SetObject(nullptr);
876  if (lnk == fFirst.get()) {
877  fFirst = lnk->fNext;
878  // lnk is still alive as we have either fLast
879  // or the 'new' fFirst->fPrev pointing to it.
880  if (lnk == fLast.get()) {
881  fLast.reset();
882  fFirst.reset();
883  } else
884  fFirst->fPrev.reset();
885  // DeleteLink(lnk);
886  } else if (lnk == fLast.get()) {
887  fLast = lnk->fPrev.lock();
888  fLast->fNext.reset();
889  // DeleteLink(lnk);
890  } else {
891  lnk->Next()->fPrev = lnk->fPrev;
892  lnk->Prev()->fNext = lnk->fNext;
893  // DeleteLink(lnk);
894  }
895  fSize--;
896  fCache.reset();
897  Changed();
898 
899  return obj;
900 }
901 
902 ////////////////////////////////////////////////////////////////////////////////
903 /// Remove the last object of the list.
904 
906 {
909 
910  TObjLink *lnk = fLast.get();
911  if (!lnk) return;
912 
913  lnk->SetObject(nullptr);
914  if (lnk == fFirst.get()) {
915  fFirst.reset();
916  fLast.reset();
917  } else {
918  fLast = lnk->fPrev.lock();
919  fLast->fNext.reset();
920  }
921  // DeleteLink(lnk);
922 
923  fSize--;
924  fCache.reset();
925  Changed();
926 }
927 
928 ////////////////////////////////////////////////////////////////////////////////
929 /// Sort linked list. Real sorting is done in private function DoSort().
930 /// The list can only be sorted when is contains objects of a sortable
931 /// class.
932 
933 void TList::Sort(Bool_t order)
934 {
937 
938  if (!fFirst) return;
939 
940  fAscending = order;
941 
942  if (!fFirst->GetObject()->IsSortable()) {
943  Error("Sort", "objects in list are not sortable");
944  return;
945  }
946 
947  DoSort(&fFirst, fSize);
948 
949  // correct back links
950  std::shared_ptr<TObjLink> ol, lnk = fFirst;
951 
952  if (lnk.get()) lnk->fPrev.reset();
953  while ((ol = lnk)) {
954  lnk = lnk->fNext;
955  if (lnk)
956  lnk->fPrev = ol;
957  else
958  fLast = ol;
959  }
960  fSorted = kTRUE;
961 }
962 
963 ////////////////////////////////////////////////////////////////////////////////
964 /// Compares the objects stored in the TObjLink objects.
965 /// Depending on the flag IsAscending() the function returns
966 /// true if the object in l1 <= l2 (ascending) or l2 <= l1 (descending).
967 
969 {
970  Int_t cmp = l1->GetObject()->Compare(l2->GetObject());
971 
972  if ((IsAscending() && cmp <=0) || (!IsAscending() && cmp > 0))
973  return kTRUE;
974  return kFALSE;
975 }
976 
977 ////////////////////////////////////////////////////////////////////////////////
978 /// Sort linked list.
979 
980 std::shared_ptr<TObjLink> *TList::DoSort(std::shared_ptr<TObjLink> *head, Int_t n)
981 {
984 
985  std::shared_ptr<TObjLink> p1, p2, *h2, *t2;
986 
987  switch (n) {
988  case 0:
989  return head;
990 
991  case 1:
992  return &((*head)->fNext);
993 
994  case 2:
995  p2 = (p1 = *head)->fNext;
996  if (LnkCompare(p1, p2)) return &(p2->fNext);
997  p1->fNext = (*head = p2)->fNext;
998  return &((p2->fNext = p1)->fNext);
999  }
1000 
1001  int m;
1002  n -= m = n / 2;
1003 
1004  t2 = DoSort(h2 = DoSort(head, n), m);
1005 
1006  if (LnkCompare((p1 = *head), (p2 = *h2))) {
1007  do {
1008  if (!--n) return *h2 = p2, t2;
1009  } while (LnkCompare((p1 = *(head = &(p1->fNext))), p2));
1010  }
1011 
1012  while (1) {
1013  *head = p2;
1014  do {
1015  if (!--m) return *h2 = *t2, *t2 = p1, h2;
1016  } while (!LnkCompare(p1, (p2 = *(head = &(p2->fNext)))));
1017  *head = p1;
1018  do {
1019  if (!--n) return *h2 = p2, t2;
1020  } while (LnkCompare((p1 = *(head = &(p1->fNext))), p2));
1021  }
1022 }
1023 
1024 /** \class TObjLink
1025 Wrapper around a TObject so it can be stored in a TList.
1026 */
1027 
1028 ////////////////////////////////////////////////////////////////////////////////
1029 /// Insert a new link in the chain.
1030 
1031 void TList::InsertAfter(const TObjLinkPtr_t &newlink, const TObjLinkPtr_t &prev)
1032 {
1033  newlink->fNext = prev->fNext;
1034  newlink->fPrev = prev;
1035  prev->fNext = newlink;
1036  if (newlink->fNext)
1037  newlink->fNext->fPrev = newlink;
1038 }
1039 
1040 /** \class TListIter
1041 Iterator of linked list.
1042 */
1043 
1045 
1046 ////////////////////////////////////////////////////////////////////////////////
1047 /// Create a new list iterator. By default the iteration direction
1048 /// is kIterForward. To go backward use kIterBackward.
1049 
1051  : fList(l), fCurCursor(0), fCursor(0), fDirection(dir), fStarted(kFALSE)
1052 {
1054 }
1055 
1056 ////////////////////////////////////////////////////////////////////////////////
1057 /// Copy ctor.
1058 
1060 {
1062 
1063  fList = iter.fList;
1064  fCurCursor = iter.fCurCursor;
1065  fCursor = iter.fCursor;
1066  fDirection = iter.fDirection;
1067  fStarted = iter.fStarted;
1068 }
1069 
1070 ////////////////////////////////////////////////////////////////////////////////
1071 /// Overridden assignment operator.
1072 
1074 {
1075 
1076  const TListIter *rhs1 = dynamic_cast<const TListIter *>(&rhs);
1077  if (this != &rhs && rhs1) {
1079  TIterator::operator=(rhs);
1080  fList = rhs1->fList;
1081  fCurCursor = rhs1->fCurCursor;
1082  fCursor = rhs1->fCursor;
1083  fDirection = rhs1->fDirection;
1084  fStarted = rhs1->fStarted;
1085  }
1086  return *this;
1087 }
1088 
1089 ////////////////////////////////////////////////////////////////////////////////
1090 /// Overloaded assignment operator.
1091 
1093 {
1094  if (this != &rhs) {
1096  TIterator::operator=(rhs);
1097  fList = rhs.fList;
1098  fCurCursor = rhs.fCurCursor;
1099  fCursor = rhs.fCursor;
1100  fDirection = rhs.fDirection;
1101  fStarted = rhs.fStarted;
1102  }
1103  return *this;
1104 }
1105 
1106 ////////////////////////////////////////////////////////////////////////////////
1107 /// Return next object in the list. Returns 0 when no more objects in list.
1108 
1110 {
1111  if (!fList) return 0;
1112 
1114 
1115  if (fDirection == kIterForward) {
1116  if (!fStarted) {
1117  fCursor = fList->fFirst;
1118  fStarted = kTRUE;
1119  }
1120  fCurCursor = fCursor;
1121  if (fCursor) {
1122  auto next = fCursor = fCursor->NextSP();
1123  }
1124  } else {
1125  if (!fStarted) {
1126  fCursor = fList->fLast;
1127  fStarted = kTRUE;
1128  }
1129  fCurCursor = fCursor;
1130  if (fCursor) fCursor = fCursor->PrevSP();
1131  }
1132 
1133  if (fCurCursor) return fCurCursor->GetObject();
1134  return 0;
1135 }
1136 
1137 ////////////////////////////////////////////////////////////////////////////////
1138 /// Returns the object option stored in the list.
1139 
1141 {
1142  if (fCurCursor) return fCurCursor->GetOption();
1143  return "";
1144 }
1145 
1146 ////////////////////////////////////////////////////////////////////////////////
1147 /// Sets the object option stored in the list.
1148 
1150 {
1151  if (fCurCursor) fCurCursor->SetOption(option);
1152 }
1153 
1154 ////////////////////////////////////////////////////////////////////////////////
1155 /// Reset list iterator.
1156 
1158 {
1160  fStarted = kFALSE;
1161 }
1162 
1163 ////////////////////////////////////////////////////////////////////////////////
1164 /// This operator compares two TIterator objects.
1165 
1167 {
1168  if (IsA() == aIter.IsA()) {
1169  // We compared equal only two iterator of the same type.
1170  // Since this is a function of TListIter, we consequently know that
1171  // both this and aIter are of type inheriting from TListIter.
1172  const TListIter &iter(dynamic_cast<const TListIter &>(aIter));
1173  return (fCurCursor != iter.fCurCursor);
1174  }
1175  return false; // for base class we don't implement a comparison
1176 }
1177 
1178 ////////////////////////////////////////////////////////////////////////////////
1179 /// This operator compares two TListIter objects.
1180 
1182 {
1183  return (fCurCursor != aIter.fCurCursor);
1184 }
1185 
1186 ////////////////////////////////////////////////////////////////////////////////
1187 /// Stream all objects in the collection to or from the I/O buffer.
1188 
1189 void TList::Streamer(TBuffer &b)
1190 {
1192 
1193  Int_t nobjects;
1194  UChar_t nch;
1195  Int_t nbig;
1196  TObject *obj;
1197  UInt_t R__s, R__c;
1198 
1199  if (b.IsReading()) {
1200  Clear(); // Get rid of old data if any.
1201  Version_t v = b.ReadVersion(&R__s, &R__c);
1202  if (v > 3) {
1203  TObject::Streamer(b);
1204  fName.Streamer(b);
1205  b >> nobjects;
1206  string readOption;
1207  for (Int_t i = 0; i < nobjects; i++) {
1208  b >> obj;
1209  b >> nch;
1210  if (v > 4 && nch == 255) {
1211  b >> nbig;
1212  } else {
1213  nbig = nch;
1214  }
1215  readOption.resize(nbig,'\0');
1216  b.ReadFastArray((char*) readOption.data(),nbig);
1217  if (obj) { // obj can be null if the class had a custom streamer and we do not have the shared library nor a streamerInfo.
1218  if (nch) {
1219  Add(obj,readOption.c_str());
1220  } else {
1221  Add(obj);
1222  }
1223  }
1224  }
1225  b.CheckByteCount(R__s, R__c,TList::IsA());
1226  return;
1227  }
1228 
1229  // process old versions when TList::Streamer was in TCollection::Streamer
1230  if (v > 2)
1231  TObject::Streamer(b);
1232  if (v > 1)
1233  fName.Streamer(b);
1234  b >> nobjects;
1235  for (Int_t i = 0; i < nobjects; i++) {
1236  b >> obj;
1237  Add(obj);
1238  }
1239  b.CheckByteCount(R__s, R__c,TList::IsA());
1240 
1241  } else {
1243 
1244  R__c = b.WriteVersion(TList::IsA(), kTRUE);
1245  TObject::Streamer(b);
1246  fName.Streamer(b);
1247  nobjects = GetSize();
1248  b << nobjects;
1249 
1250  TObjLink *lnk = fFirst.get();
1251  while (lnk) {
1252  obj = lnk->GetObject();
1253  b << obj;
1254 
1255  nbig = strlen(lnk->GetAddOption());
1256  if (nbig > 254) {
1257  nch = 255;
1258  b << nch;
1259  b << nbig;
1260  } else {
1261  nch = UChar_t(nbig);
1262  b << nch;
1263  }
1264  b.WriteFastArray(lnk->GetAddOption(),nbig);
1265 
1266  lnk = lnk->Next();
1267  }
1268  b.SetByteCount(R__c, kTRUE);
1269  }
1270 }
std::string GetName(const std::string &scope_name)
Definition: Cppyy.cxx:145
virtual void AddAt(TObject *obj, Int_t idx)
Insert object at position idx in the list.
Definition: TList.cxx:303
Bool_t IsReading() const
Definition: TBuffer.h:83
virtual void Delete(Option_t *option="")
Remove all objects from the list AND delete all heap based objects.
Definition: TList.cxx:467
Bool_t fStarted
Definition: TList.h:209
#define R__COLLECTION_READ_GUARD()
Definition: TCollection.h:126
auto * m
Definition: textangle.C:8
short Version_t
Definition: RtypesCore.h:61
const char Option_t
Definition: RtypesCore.h:62
void InsertAfter(const TObjLinkPtr_t &newlink, const TObjLinkPtr_t &prev)
Insert a new link in the chain.
Definition: TList.cxx:1031
virtual void RemoveLast()
Remove the last object of the list.
Definition: TList.cxx:905
TObjLink * LinkAt(Int_t idx) const
sorting order (when calling Sort() or for TSortedList)
Definition: TList.cxx:701
TObjLinkPtr_t fFirst
Definition: TList.h:52
virtual TObject * Last() const
Return the last object in the list. Returns 0 when list is empty.
Definition: TList.cxx:689
virtual void AddFirst(TObject *obj)
Add object at the beginning of the list.
Definition: TList.cxx:97
Buffer base class used for serializing objects.
Definition: TBuffer.h:40
const TList * fList
Definition: TList.h:205
virtual Int_t CheckByteCount(UInt_t startpos, UInt_t bcnt, const TClass *clss)=0
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition: TObject.h:172
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
STL namespace.
virtual UInt_t WriteVersion(const TClass *cl, Bool_t useBcnt=kFALSE)=0
TObject * Next()
Return next object in the list. Returns 0 when no more objects in list.
Definition: TList.cxx:1109
Iterator abstract base class.
Definition: TIterator.h:30
Iterator of linked list.
Definition: TList.h:197
virtual void AddLast(TObject *obj)
Add object at the end of the list.
Definition: TList.cxx:149
virtual TObject * FindObject(const char *name) const
Delete a TObjLink object.
Definition: TList.cxx:574
virtual void RecursiveRemove(TObject *obj)
Recursively remove this object from a list.
Definition: TObject.cxx:572
TObjLinkPtr_t fCurCursor
Definition: TList.h:206
virtual void Sort(Bool_t order=kSortAscending)
Sort linked list.
Definition: TList.cxx:933
Bool_t LnkCompare(const TObjLinkPtr_t &l1, const TObjLinkPtr_t &l2)
Compares the objects stored in the TObjLink objects.
Definition: TList.cxx:968
#define R__COLLECTION_WRITE_GUARD()
Definition: TCollection.h:125
static double p2(double t, double a, double b, double c)
Bool_t fDirection
Definition: TList.h:208
#define R__COLLECTION_READ_LOCKGUARD(mutex)
Definition: TCollection.h:433
R__EXTERN TVirtualRWMutex * gCoreMutex
const Bool_t kIterForward
Definition: TCollection.h:40
std::shared_ptr< TObjLink > TObjLinkPtr_t
Definition: TList.h:49
TObjLinkPtr_t NewOptLink(TObject *obj, Option_t *opt, const TObjLinkPtr_t &prev=nullptr)
Return a new TObjOptLink (a TObjLink that also stores the option).
Definition: TList.cxx:744
void Error(const char *location, const char *msgfmt,...)
virtual Bool_t IsEqual(const TObject *obj) const
Default equal comparison (objects are equal if they have the same address in memory).
Definition: TObject.cxx:483
virtual TIterator * MakeIterator(Bool_t dir=kIterForward) const
Return a list iterator.
Definition: TList.cxx:718
A doubly linked list.
Definition: TList.h:44
virtual ~TList()
Delete the list.
Definition: TList.cxx:89
virtual TObject * First() const
Return the first object in the list. Returns 0 when list is empty.
Definition: TList.cxx:655
SVector< double, 2 > v
Definition: Dict.h:5
TListIter()
Definition: TList.h:211
virtual TObject * Remove(TObject *obj)
Remove object from the list.
Definition: TList.cxx:818
virtual TObject * Before(const TObject *obj) const
Returns the object before object obj.
Definition: TList.cxx:368
TObjLinkPtr_t fCursor
Definition: TList.h:207
unsigned int UInt_t
Definition: RtypesCore.h:42
virtual void SetByteCount(UInt_t cntpos, Bool_t packInVersion=kFALSE)=0
virtual TObject * After(const TObject *obj) const
Returns the object after object obj.
Definition: TList.cxx:327
static double p1(double t, double a, double b)
virtual TObject * At(Int_t idx) const
Returns the object at position idx. Returns 0 if idx is out of range.
Definition: TList.cxx:354
virtual void AddBefore(const TObject *before, TObject *obj)
Insert object before object before in the list.
Definition: TList.cxx:193
virtual void ReadFastArray(Bool_t *b, Int_t n)=0
virtual void WriteFastArray(const Bool_t *b, Int_t n)=0
const Bool_t kFALSE
Definition: RtypesCore.h:88
static void GarbageCollect(TObject *obj)
Add to the list of things to be cleaned up.
#define R__COLLECTION_ITER_GUARD(collection)
Definition: TCollection.h:127
void Add(THist< DIMENSIONS, PRECISION_TO, STAT_TO... > &to, const THist< DIMENSIONS, PRECISION_FROM, STAT_FROM... > &from)
Add two histograms.
Definition: THist.hxx:308
#define ClassImp(name)
Definition: Rtypes.h:359
TObjLinkPtr_t * DoSort(TObjLinkPtr_t *head, Int_t n)
Sort linked list.
Definition: TList.cxx:980
virtual void Clear(Option_t *option="")
Remove all objects from the list.
Definition: TList.cxx:399
void SetOption(Option_t *option)
Sets the object option stored in the list.
Definition: TList.cxx:1149
virtual void AddAfter(const TObject *after, TObject *obj)
Insert object after object after in the list.
Definition: TList.cxx:247
Mother of all ROOT objects.
Definition: TObject.h:37
auto * l
Definition: textangle.C:4
virtual void RecursiveRemove(TObject *obj)
Remove object from this collection and recursively remove the object from all other objects (and coll...
Definition: TList.cxx:760
virtual TIterator & operator=(const TIterator &)
Definition: TIterator.h:37
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
Bool_t operator!=(const TIterator &aIter) const
This operator compares two TIterator objects.
Definition: TList.cxx:1166
void Reset()
Reset list iterator.
Definition: TList.cxx:1157
#define R__COLLECTION_WRITE_LOCKGUARD(mutex)
Definition: TCollection.h:436
unsigned char UChar_t
Definition: RtypesCore.h:34
Definition: first.py:1
TIterator & operator=(const TIterator &rhs)
Overridden assignment operator.
Definition: TList.cxx:1073
const Bool_t kTRUE
Definition: RtypesCore.h:87
virtual TObject ** GetObjectRef(const TObject *obj) const
Return address of pointer to obj.
Definition: TList.cxx:667
const Int_t n
Definition: legend1.C:16
Option_t * GetOption() const
Returns the object option stored in the list.
Definition: TList.cxx:1140
char name[80]
Definition: TGX11.cxx:109
TObjLinkPtr_t fLast
pointer to first entry in linked list
Definition: TList.h:53
virtual Version_t ReadVersion(UInt_t *start=0, UInt_t *bcnt=0, const TClass *cl=0)=0
TObjLink * FindLink(const TObject *obj, Int_t &idx) const
Returns the TObjLink object that contains object obj.
Definition: TList.cxx:624
TObjLinkPtr_t NewLink(TObject *obj, const TObjLinkPtr_t &prev=nullptr)
Return a new TObjLink.
Definition: TList.cxx:729
T1 fFirst
Definition: X11Events.mm:86