Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
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
14A doubly linked list.
15
16All classes inheriting from TObject can be
17inserted in a TList. Before being inserted into the list the object
18pointer is wrapped in a TObjLink object which contains, besides
19the object pointer also a previous and next pointer.
20
21There are several ways to iterate over a TList; in order of preference, if
22not forced by other constraints:
23
24 1. (Preferred way) Using the C++ range-based `for` or `begin()` / `end()`:
25~~~ {.cpp}
26 for(TObject *obj: *GetListOfPrimitives())
27 obj->Write();
28~~~
29 2. Using the R__FOR_EACH macro:
30~~~ {.cpp}
31 GetListOfPrimitives()->R__FOR_EACH(TObject,Paint)(option);
32~~~
33 3. Using the TList iterator TListIter (via the wrapper class TIter):
34~~~ {.cpp}
35 TIter next(GetListOfPrimitives());
36 while (TObject *obj = next())
37 obj->Draw(next.GetOption());
38~~~
39 4. Using the TList iterator TListIter and std::for_each algorithm:
40~~~ {.cpp}
41 // A function object, which will be applied to each element
42 // of the given range.
43 struct STestFunctor {
44 bool operator()(TObject *aObj) {
45 ...
46 return true;
47 }
48 }
49 ...
50 ...
51 TIter iter(mylist);
52 for_each( iter.Begin(), TIter::End(), STestFunctor() );
53~~~
54 5. Using the TObjLink list entries (that wrap the TObject*):
55~~~ {.cpp}
56 TObjLink *lnk = GetListOfPrimitives()->FirstLink();
57 while (lnk) {
58 lnk->GetObject()->Draw(lnk->GetOption());
59 lnk = lnk->Next();
60 }
61~~~
62 6. Using the TList's After() and Before() member functions:
63~~~ {.cpp}
64 TFree *idcur = this;
65 while (idcur) {
66 ...
67 ...
68 idcur = (TFree*)GetListOfFree()->After(idcur);
69 }
70~~~
71Methods 3, 4 and 5 can also easily iterate backwards using either
72a backward TIter (using argument kIterBackward) or by using
73LastLink() and lnk->Prev() or by using the Before() member.
74*/
75
76#include "TList.h"
77#include "TClass.h"
78#include "TROOT.h"
79#include "TVirtualMutex.h"
80#include "TBuffer.h"
81
82#include <string>
83
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
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
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
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
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 before object before in the list, with options.
302
304{
306
307 if (IsArgNull("AddBefore", obj)) return;
308
310
311 if (!before)
312 TList::AddFirst(obj, opt);
313 else {
314 Int_t idx;
315 TObjLink *t = FindLink(before, idx);
316 if (!t) {
317 Error("AddBefore", "before not found, object not added");
318 return;
319 }
320 if (t == fFirst.get())
321 TList::AddFirst(obj, opt);
322 else {
323 NewOptLink(obj, opt, t->fPrev.lock());
324 fSize++;
325 Changed();
326 }
327 }
328}
329
330////////////////////////////////////////////////////////////////////////////////
331/// Insert object before the specified ObjLink object. If before = 0 then add
332/// to the head of the list. An ObjLink can be obtained by looping over a list
333/// using the above describe iterator method 3. Options can be specified.
334
336{
338
339 if (IsArgNull("AddBefore", obj)) return;
340
341 if (!before)
342 TList::AddFirst(obj, opt);
343 else {
344 if (before == fFirst.get())
345 TList::AddFirst(obj, opt);
346 else {
347 NewOptLink(obj, opt, before->fPrev.lock());
348 fSize++;
349 Changed();
350 }
351 }
352}
353
354////////////////////////////////////////////////////////////////////////////////
355/// Insert object after object after in the list, with options.
356
358{
360
361 if (IsArgNull("AddAfter", obj)) return;
362
364
365 if (!after)
366 TList::AddLast(obj, opt);
367 else {
368 Int_t idx;
369 TObjLink *t = FindLink(after, idx);
370 if (!t) {
371 Error("AddAfter", "after not found, object not added");
372 return;
373 }
374 if (t == fLast.get())
375 TList::AddLast(obj, opt);
376 else {
377 NewOptLink(obj, opt, t->shared_from_this());
378 fSize++;
379 Changed();
380 }
381 }
382}
383
384////////////////////////////////////////////////////////////////////////////////
385/// Insert object after the specified ObjLink object. If after = 0 then add
386/// to the tail of the list. An ObjLink can be obtained by looping over a list
387/// using the above describe iterator method 3. Options can be specified.
388
390{
392
393 if (IsArgNull("AddAfter", obj)) return;
394
396
397 if (!after)
398 TList::AddLast(obj, opt);
399 else {
400 if (after == fLast.get())
401 TList::AddLast(obj, opt);
402 else {
403 NewOptLink(obj, opt, after->shared_from_this());
404 fSize++;
405 Changed();
406 }
407 }
408}
409
410////////////////////////////////////////////////////////////////////////////////
411/// Insert object at position idx in the list.
412
414{
416
417 if (IsArgNull("AddAt", obj)) return;
418
420
421 TObjLink *lnk = LinkAt(idx);
422 if (!lnk)
423 TList::AddLast(obj);
424 else if (lnk == fFirst.get())
425 TList::AddFirst(obj);
426 else {
427 NewLink(obj, lnk->fPrev.lock());
428 fSize++;
429 Changed();
430 }
431}
432
433////////////////////////////////////////////////////////////////////////////////
434/// Insert object at position idx in the list, with options.
435
436void TList::AddAt(TObject *obj, Int_t idx, Option_t *opt)
437{
439
440 if (IsArgNull("AddAt", obj)) return;
441
443
444 TObjLink *lnk = LinkAt(idx);
445 if (!lnk)
446 TList::AddLast(obj, opt);
447 else if (lnk == fFirst.get())
448 TList::AddFirst(obj, opt);
449 else {
450 NewOptLink(obj, opt, lnk->fPrev.lock());
451 fSize++;
452 Changed();
453 }
454}
455
456////////////////////////////////////////////////////////////////////////////////
457/// Returns the object after object obj. Obj is found using the
458/// object's IsEqual() method. Returns 0 if obj is last in list.
459
460TObject *TList::After(const TObject *obj) const
461{
463
464 TObjLink *t;
465
467
468 auto cached = fCache.lock();
469 if (cached.get() && cached->GetObject() && cached->GetObject()->IsEqual(obj)) {
470 t = cached.get();
471 ((TList*)this)->fCache = cached->fNext; //cast const away, fCache should be mutable
472 } else {
473 Int_t idx;
474 t = FindLink(obj, idx);
475 if (t) ((TList*)this)->fCache = t->fNext;
476 }
477
478 if (t && t->Next())
479 return t->Next()->GetObject();
480 else
481 return nullptr;
482}
483
484////////////////////////////////////////////////////////////////////////////////
485/// Returns the object at position idx. Returns 0 if idx is out of range.
486
488{
491
492 TObjLink *lnk = LinkAt(idx);
493 if (lnk) return lnk->GetObject();
494 return nullptr;
495}
496
497////////////////////////////////////////////////////////////////////////////////
498/// Returns the object before object obj. Obj is found using the
499/// object's IsEqual() method. Returns 0 if obj is first in list.
500
501TObject *TList::Before(const TObject *obj) const
502{
505
506 TObjLink *t;
507
508 auto cached = fCache.lock();
509 if (cached.get() && cached->GetObject() && cached->GetObject()->IsEqual(obj)) {
510 t = cached.get();
511 ((TList*)this)->fCache = cached->fPrev; //cast const away, fCache should be mutable
512 } else {
513 Int_t idx;
514 t = FindLink(obj, idx);
515 if (t) ((TList*)this)->fCache = t->fPrev;
516 }
517
518 if (t && t->Prev())
519 return t->Prev()->GetObject();
520 else
521 return nullptr;
522}
523
524////////////////////////////////////////////////////////////////////////////////
525/// Remove all objects from the list. Does not delete the objects
526/// unless the TList is the owner (set via SetOwner()) and option
527/// "nodelete" is not set.
528/// If option="nodelete" then don't delete any heap objects that were
529/// marked with the kCanDelete bit, otherwise these objects will be
530/// deleted (this option is used by THashTable::Clear()).
531
533{
536
537 Bool_t nodel = option ? (!strcmp(option, "nodelete") ? kTRUE : kFALSE) : kFALSE;
538
539 if (!nodel && IsOwner()) {
540 Delete(option);
541 return;
542 }
543
544 // In some case, for example TParallelCoord, a list (the pad's list of
545 // primitives) will contain both the container and the containees
546 // (the TParallelCoordVar) but if the Clear is being called from
547 // the destructor of the container of this list, one of the first
548 // thing done will be the remove the container (the pad) for the
549 // list (of Primitives of the canvas) that was connecting it
550 // (indirectly) to the list of cleanups.
551 // Note: The Code in TParallelCoordVar was changed (circa June 2017),
552 // to no longer have this behavior and thus rely on this code (by moving
553 // from using Draw to Paint) but the structure might still exist elsewhere
554 // so we keep this comment here.
555
556 // To preserve this connection (without introducing one when there was none),
557 // we re-use fCache to inform RecursiveRemove of the node currently
558 // being cleared/deleted.
559 while (fFirst) {
560 auto tlk = fFirst;
561 fFirst = fFirst->fNext;
562 fSize--;
563
564
565 // Make node available to RecursiveRemove
566 tlk->fNext.reset();
567 tlk->fPrev.reset();
568 fCache = tlk;
569
570 // delete only heap objects marked OK to clear
571 auto obj = tlk->GetObject();
572 if (!nodel && obj) {
574 Error("Clear", "A list is accessing an object (%p) already deleted (list name = %s)",
575 obj, GetName());
576 } else if (obj->IsOnHeap()) {
577 if (obj->TestBit(kCanDelete)) {
580 }
581 }
582 }
583 }
584 // delete tlk;
585 }
586 fFirst.reset();
587 fLast.reset();
588 fCache.reset();
589 fSize = 0;
590 Changed();
591}
592
593////////////////////////////////////////////////////////////////////////////////
594/// Remove all objects from the list AND delete all heap based objects.
595/// If option="slow" then keep list consistent during delete. This allows
596/// recursive list operations during the delete (e.g. during the dtor
597/// of an object in this list one can still access the list to search for
598/// other not yet deleted objects).
599
601{
604
605 Bool_t slow = option ? (!strcmp(option, "slow") ? kTRUE : kFALSE) : kFALSE;
606
607 TList removeDirectory; // need to deregister these from their directory
608
609 if (slow) {
610
611 // In some case, for example TParallelCoord, a list (the pad's list of
612 // primitives) will contain both the container and the containees
613 // (the TParallelCoorVar) but if the Clear is being called from
614 // the destructor of the container of this list, one of the first
615 // thing done will be the remove the container (the pad) for the
616 // list (of Primitives of the canvas) that was connecting it
617 // (indirectly) to the list of cleanups.
618
619 // To preserve this connection (without introducing one when there was none),
620 // we re-use fCache to inform RecursiveRemove of the node currently
621 // being cleared/deleted.
622 while (fFirst) {
623 auto tlk = fFirst;
624 fFirst = fFirst->fNext;
625 fSize--;
626
627 // Make node available to RecursiveRemove
628 tlk->fNext.reset();
629 tlk->fPrev.reset();
630 fCache = tlk;
631
632 // delete only heap objects
633 auto obj = tlk->GetObject();
634 if (obj && ROOT::Detail::HasBeenDeleted(obj))
635 Error("Delete", "A list is accessing an object (%p) already deleted (list name = %s)",
636 obj, GetName());
637 else if (obj && obj->IsOnHeap())
639 else if (obj && obj->IsA()->GetDirectoryAutoAdd())
640 removeDirectory.Add(obj);
641
642 // delete tlk;
643 }
644
645 fFirst.reset();
646 fLast.reset();
647 fCache.reset();
648 fSize = 0;
649
650 } else {
651
652 auto first = fFirst; //pointer to first entry in linked list
653 fFirst.reset();
654 fLast.reset();
655 fCache.reset();
656 fSize = 0;
657 while (first) {
658 auto tlk = first;
659 first = first->fNext;
660 // delete only heap objects
661 auto obj = tlk->GetObject();
662 tlk->SetObject(nullptr);
663 if (obj && ROOT::Detail::HasBeenDeleted(obj))
664 Error("Delete", "A list is accessing an object (%p) already deleted (list name = %s)",
665 obj, GetName());
666 else if (obj && obj->IsOnHeap())
668 else if (obj && obj->IsA()->GetDirectoryAutoAdd())
669 removeDirectory.Add(obj);
670
671 // The formerly first token, when tlk goes out of scope has no more references
672 // because of the fFirst.reset()
673 }
674 }
675
676 // These objects cannot expect to have a valid TDirectory anymore;
677 // e.g. because *this is the TDirectory's list of objects. Even if
678 // not, they are supposed to be deleted, so we can as well unregister
679 // them from their directory, even if they are stack-based:
681 TObject* dirRem = nullptr;
682 while ((dirRem = iRemDir())) {
683 (*dirRem->IsA()->GetDirectoryAutoAdd())(dirRem, nullptr);
684 }
685 Changed();
686}
687
688#if 0
689////////////////////////////////////////////////////////////////////////////////
690/// Delete a TObjLink object.
691
692void TList::DeleteLink(TObjLink *lnk)
693{
695
696 lnk->fNext = lnk->fPrev = 0;
697 lnk->fObject = 0;
698 delete lnk;
699}
700#endif
701
702////////////////////////////////////////////////////////////////////////////////
703/// Find an object in this list using its name. Requires a sequential
704/// scan till the object has been found. Returns 0 if object with specified
705/// name is not found. This method overrides the generic FindObject()
706/// of TCollection for efficiency reasons.
707
708TObject *TList::FindObject(const char *name) const
709{
711
712 if (!name)
713 return nullptr;
714
716
717 for (TObjLink *lnk = FirstLink(); lnk != nullptr; lnk = lnk->Next()) {
718 if (TObject *obj = lnk->GetObject()) {
719 const char *objname = obj->GetName();
720 if (objname && strcmp(name, objname) == 0)
721 return obj;
722 }
723 }
724
725 return nullptr;
726}
727
728////////////////////////////////////////////////////////////////////////////////
729/// Find an object in this list using the object's IsEqual()
730/// member function. Requires a sequential scan till the object has
731/// been found. Returns 0 if object is not found.
732/// This method overrides the generic FindObject() of TCollection for
733/// efficiency reasons.
734
736{
738
739 if (!obj)
740 return nullptr;
741
743
745
746 while (lnk) {
747 TObject *ob = lnk->GetObject();
748 if (ob->IsEqual(obj)) return ob;
749 lnk = lnk->Next();
750 }
751 return nullptr;
752}
753
754////////////////////////////////////////////////////////////////////////////////
755/// Returns the TObjLink object that contains object obj. In idx it returns
756/// the position of the object in the list.
757
758TObjLink *TList::FindLink(const TObject *obj, Int_t &idx) const
759{
761
762 if (!obj)
763 return nullptr;
764
766
767 if (!fFirst) return nullptr;
768
770 TObjLink *lnk = fFirst.get();
771 idx = 0;
772
773 while (lnk) {
774 object = lnk->GetObject();
775 if (object) {
776 if (!ROOT::Detail::HasBeenDeleted(object)) {
777 if (object->IsEqual(obj)) return lnk;
778 }
779 }
780 lnk = lnk->Next();
781 idx++;
782 }
783 return nullptr;
784}
785
786////////////////////////////////////////////////////////////////////////////////
787/// Return the first object in the list. Returns 0 when list is empty.
788
790{
793
794 if (fFirst) return fFirst->GetObject();
795 return nullptr;
796}
797
798////////////////////////////////////////////////////////////////////////////////
799/// Return address of pointer to obj
800
802{
804
805 if (!obj)
806 return nullptr;
807
809
811
812 while (lnk) {
813 TObject *ob = lnk->GetObject();
814 if (ob->IsEqual(obj)) return lnk->GetObjectRef();
815 lnk = lnk->Next();
816 }
817 return nullptr;
818}
819
820////////////////////////////////////////////////////////////////////////////////
821/// Return the last object in the list. Returns 0 when list is empty.
822
824{
827
828 if (fLast) return fLast->GetObject();
829 return nullptr;
830}
831
832////////////////////////////////////////////////////////////////////////////////
833/// Return the TObjLink object at index idx.
834
836{
839
840 Int_t i = 0;
841 TObjLink *lnk = fFirst.get();
842 while (i < idx && lnk) {
843 i++;
844 lnk = lnk->Next();
845 }
846 return lnk;
847}
848
849////////////////////////////////////////////////////////////////////////////////
850/// Return a list iterator.
851
859
860////////////////////////////////////////////////////////////////////////////////
861/// Return a new TObjLink.
862
864{
867
868 auto newlink = std::make_shared<TObjLink>(obj);
869 if (prev) {
870 InsertAfter(newlink, prev);
871 }
872 return newlink;
873}
874
875////////////////////////////////////////////////////////////////////////////////
876/// Return a new TObjOptLink (a TObjLink that also stores the option).
877
879{
882
883 auto newlink = std::make_shared<TObjOptLink>(obj, opt);
884 if (prev) {
885 InsertAfter(newlink, prev);
886 }
887 return newlink;
888}
889
890////////////////////////////////////////////////////////////////////////////////
891/// Remove object from this collection and recursively remove the object
892/// from all other objects (and collections).
893
895{
896 // Note, we can assume that the Collection Read lock is held, see
897 // THashList::RecursiveRemove for a more complete discussion.
898 if (!obj || (fSize == 0 && fCache.expired()))
899 return;
900
902
903 // When fCache is set and has no previous and next node, it represents
904 // the node being cleared and/or deleted.
905 {
906 auto cached = fCache.lock();
907 if (cached && cached->fNext.get() == nullptr && cached->fPrev.lock().get() == nullptr) {
908 TObject *ob = cached->GetObject();
910 ob->RecursiveRemove(obj);
911 }
912 }
913 }
914
915 auto lnk = fFirst;
916 decltype(lnk) next;
917 while (lnk.get()) {
918 next = lnk->fNext;
919 TObject *ob = lnk->GetObject();
921 if (ob->IsEqual(obj)) {
922 lnk->SetObject(nullptr);
923 if (lnk == fFirst) {
924 fFirst = next;
925 if (lnk == fLast)
926 fLast = fFirst;
927 else
928 fFirst->fPrev.reset();
929 // DeleteLink(lnk);
930 } else if (lnk == fLast) {
931 fLast = lnk->fPrev.lock();
932 fLast->fNext.reset();
933 // DeleteLink(lnk);
934 } else {
935 lnk->Prev()->fNext = next;
936 lnk->Next()->fPrev = lnk->fPrev;
937 // DeleteLink(lnk);
938 }
939 fSize--;
940 fCache.reset();
941 Changed();
942 } else
943 ob->RecursiveRemove(obj);
944 }
945 lnk = next;
946 }
947}
948
949////////////////////////////////////////////////////////////////////////////////
950/// Remove object from the list.
951
953{
955
956 if (!obj) return nullptr;
957
958 Int_t idx;
959 TObjLink *lnk = FindLink(obj, idx);
960
961 if (!lnk) return nullptr;
962
963 // return object found, which may be (pointer wise) different than the
964 // input object (depending on what IsEqual() is doing)
965
967
968 TObject *ob = lnk->GetObject();
969 lnk->SetObject(nullptr);
970 if (lnk == fFirst.get()) {
971 fFirst = lnk->fNext;
972 // lnk is still alive as we have either fLast
973 // or the 'new' fFirst->fPrev pointing to it.
974 if (lnk == fLast.get()) {
975 fLast.reset();
976 fFirst.reset();
977 } else
978 fFirst->fPrev.reset();
979 //DeleteLink(lnk);
980 } else if (lnk == fLast.get()) {
981 fLast = lnk->fPrev.lock();
982 fLast->fNext.reset();
983 //DeleteLink(lnk);
984 } else {
985 lnk->Next()->fPrev = lnk->fPrev;
986 lnk->Prev()->fNext = lnk->fNext;
987 //DeleteLink(lnk);
988 }
989 fSize--;
990 fCache.reset();
991 Changed();
992
993 return ob;
994}
995
996////////////////////////////////////////////////////////////////////////////////
997/// Remove object link (and therefore the object it contains)
998/// from the list.
999
1001{
1003
1004 if (!lnk) return nullptr;
1005
1007
1008 TObject *obj = lnk->GetObject();
1009 lnk->SetObject(nullptr);
1010 if (lnk == fFirst.get()) {
1011 fFirst = lnk->fNext;
1012 // lnk is still alive as we have either fLast
1013 // or the 'new' fFirst->fPrev pointing to it.
1014 if (lnk == fLast.get()) {
1015 fLast.reset();
1016 fFirst.reset();
1017 } else
1018 fFirst->fPrev.reset();
1019 // DeleteLink(lnk);
1020 } else if (lnk == fLast.get()) {
1021 fLast = lnk->fPrev.lock();
1022 fLast->fNext.reset();
1023 // DeleteLink(lnk);
1024 } else {
1025 lnk->Next()->fPrev = lnk->fPrev;
1026 lnk->Prev()->fNext = lnk->fNext;
1027 // DeleteLink(lnk);
1028 }
1029 fSize--;
1030 fCache.reset();
1031 Changed();
1032
1033 return obj;
1034}
1035
1036////////////////////////////////////////////////////////////////////////////////
1037/// Remove the last object of the list.
1038
1040{
1043
1044 TObjLink *lnk = fLast.get();
1045 if (!lnk) return;
1046
1047 lnk->SetObject(nullptr);
1048 if (lnk == fFirst.get()) {
1049 fFirst.reset();
1050 fLast.reset();
1051 } else {
1052 fLast = lnk->fPrev.lock();
1053 fLast->fNext.reset();
1054 }
1055 // DeleteLink(lnk);
1056
1057 fSize--;
1058 fCache.reset();
1059 Changed();
1060}
1061
1062////////////////////////////////////////////////////////////////////////////////
1063/// Sort linked list. Real sorting is done in private function DoSort().
1064/// The list can only be sorted when is contains objects of a sortable
1065/// class.
1066
1068{
1071
1072 if (!fFirst) return;
1073
1074 fAscending = order;
1075
1076 if (!fFirst->GetObject()->IsSortable()) {
1077 Error("Sort", "objects in list are not sortable");
1078 return;
1079 }
1080
1081 DoSort(&fFirst, fSize);
1082
1083 // correct back links
1084 std::shared_ptr<TObjLink> ol, lnk = fFirst;
1085
1086 if (lnk.get()) lnk->fPrev.reset();
1087 while ((ol = lnk)) {
1088 lnk = lnk->fNext;
1089 if (lnk)
1090 lnk->fPrev = ol;
1091 else
1092 fLast = ol;
1093 }
1094 fSorted = kTRUE;
1095}
1096
1097////////////////////////////////////////////////////////////////////////////////
1098/// Compares the objects stored in the TObjLink objects.
1099/// Depending on the flag IsAscending() the function returns
1100/// true if the object in l1 <= l2 (ascending) or l2 <= l1 (descending).
1101
1103{
1104 Int_t cmp = l1->GetObject()->Compare(l2->GetObject());
1105
1106 if ((IsAscending() && cmp <=0) || (!IsAscending() && cmp > 0))
1107 return kTRUE;
1108 return kFALSE;
1109}
1110
1111////////////////////////////////////////////////////////////////////////////////
1112/// Sort linked list.
1113
1114std::shared_ptr<TObjLink> *TList::DoSort(std::shared_ptr<TObjLink> *head, Int_t n)
1115{
1118
1119 std::shared_ptr<TObjLink> p1, p2, *h2, *t2;
1120
1121 switch (n) {
1122 case 0:
1123 return head;
1124
1125 case 1:
1126 return &((*head)->fNext);
1127
1128 case 2:
1129 p2 = (p1 = *head)->fNext;
1130 if (LnkCompare(p1, p2)) return &(p2->fNext);
1131 p1->fNext = (*head = p2)->fNext;
1132 return &((p2->fNext = p1)->fNext);
1133 }
1134
1135 int m;
1136 n -= m = n / 2;
1137
1138 t2 = DoSort(h2 = DoSort(head, n), m);
1139
1140 if (LnkCompare((p1 = *head), (p2 = *h2))) {
1141 do {
1142 if (!--n) return *h2 = p2, t2;
1143 } while (LnkCompare((p1 = *(head = &(p1->fNext))), p2));
1144 }
1145
1146 while (1) {
1147 *head = p2;
1148 do {
1149 if (!--m) return *h2 = *t2, *t2 = p1, h2;
1150 } while (!LnkCompare(p1, (p2 = *(head = &(p2->fNext)))));
1151 *head = p1;
1152 do {
1153 if (!--n) return *h2 = p2, t2;
1154 } while (LnkCompare((p1 = *(head = &(p1->fNext))), p2));
1155 }
1156}
1157
1158/** \class TObjLink
1159Wrapper around a TObject so it can be stored in a TList.
1160*/
1161
1162////////////////////////////////////////////////////////////////////////////////
1163/// Insert a new link in the chain.
1164
1166{
1167 newlink->fNext = prev->fNext;
1168 newlink->fPrev = prev;
1169 prev->fNext = newlink;
1170 if (newlink->fNext)
1171 newlink->fNext->fPrev = newlink;
1172}
1173
1174/** \class TListIter
1175Iterator of linked list.
1176\note See TList documentation for examples on how to loop with this
1177iterator, and TCollection documentation for more modern alternatives
1178that dynamically cast the derived class.
1179*/
1180
1181
1182////////////////////////////////////////////////////////////////////////////////
1183/// Create a new list iterator. By default the iteration direction
1184/// is kIterForward. To go backward use kIterBackward.
1185
1187 : fList(l), fCurCursor(nullptr), fCursor(nullptr), fDirection(dir), fStarted(kFALSE)
1188{
1190}
1191
1192////////////////////////////////////////////////////////////////////////////////
1193/// Copy ctor.
1194
1196{
1198
1199 fList = iter.fList;
1200 fCurCursor = iter.fCurCursor;
1201 fCursor = iter.fCursor;
1202 fDirection = iter.fDirection;
1203 fStarted = iter.fStarted;
1204}
1205
1206////////////////////////////////////////////////////////////////////////////////
1207/// Overridden assignment operator.
1208
1210{
1211
1212 const TListIter *rhs1 = dynamic_cast<const TListIter *>(&rhs);
1213 if (this != &rhs && rhs1) {
1215 fList = rhs1->fList;
1216 fCurCursor = rhs1->fCurCursor;
1217 fCursor = rhs1->fCursor;
1218 fDirection = rhs1->fDirection;
1219 fStarted = rhs1->fStarted;
1220 }
1221 return *this;
1222}
1223
1224////////////////////////////////////////////////////////////////////////////////
1225/// Overloaded assignment operator.
1226
1228{
1229 if (this != &rhs) {
1231 fList = rhs.fList;
1232 fCurCursor = rhs.fCurCursor;
1233 fCursor = rhs.fCursor;
1234 fDirection = rhs.fDirection;
1235 fStarted = rhs.fStarted;
1236 }
1237 return *this;
1238}
1239
1240////////////////////////////////////////////////////////////////////////////////
1241/// Return next object in the list. Returns 0 when no more objects in list.
1242
1244{
1245 if (!fList) return nullptr;
1246
1248
1249 if (fDirection == kIterForward) {
1250 if (!fStarted) {
1251 fCursor = fList->fFirst;
1252 fStarted = kTRUE;
1253 }
1255 if (fCursor) {
1256 auto next = fCursor = fCursor->NextSP();
1257 }
1258 } else {
1259 if (!fStarted) {
1260 fCursor = fList->fLast;
1261 fStarted = kTRUE;
1262 }
1264 if (fCursor) fCursor = fCursor->PrevSP();
1265 }
1266
1267 if (fCurCursor) return fCurCursor->GetObject();
1268 return nullptr;
1269}
1270
1271////////////////////////////////////////////////////////////////////////////////
1272/// Returns the object option stored in the list.
1273
1275{
1276 if (fCurCursor) return fCurCursor->GetOption();
1277 return "";
1278}
1279
1280////////////////////////////////////////////////////////////////////////////////
1281/// Sets the object option stored in the list.
1282
1284{
1285 if (fCurCursor) fCurCursor->SetOption(option);
1286}
1287
1288////////////////////////////////////////////////////////////////////////////////
1289/// Reset list iterator.
1290
1296
1297////////////////////////////////////////////////////////////////////////////////
1298/// This operator compares two TIterator objects.
1299
1301{
1302 if (IsA() == aIter.IsA()) {
1303 // We compared equal only two iterator of the same type.
1304 // Since this is a function of TListIter, we consequently know that
1305 // both this and aIter are of type inheriting from TListIter.
1306 const TListIter &iter(dynamic_cast<const TListIter &>(aIter));
1307 return (fCurCursor != iter.fCurCursor);
1308 }
1309 return false; // for base class we don't implement a comparison
1310}
1311
1312////////////////////////////////////////////////////////////////////////////////
1313/// This operator compares two TListIter objects.
1314
1316{
1317 return (fCurCursor != aIter.fCurCursor);
1318}
1319
1320////////////////////////////////////////////////////////////////////////////////
1321/// Stream all objects in the collection to or from the I/O buffer.
1322
1324{
1326
1328 UChar_t nch;
1329 Int_t nbig;
1330 TObject *obj;
1331 UInt_t R__s, R__c;
1332
1333 if (b.IsReading()) {
1334 Clear(); // Get rid of old data if any.
1335 Version_t v = b.ReadVersion(&R__s, &R__c);
1336 if (v > 3) {
1338 fName.Streamer(b);
1339 b >> nobjects;
1340 std::string readOption;
1341 for (Int_t i = 0; i < nobjects; i++) {
1342 b >> obj;
1343 b >> nch;
1344 if (v > 4 && nch == 255) {
1345 b >> nbig;
1346 } else {
1347 nbig = nch;
1348 }
1349 readOption.resize(nbig,'\0');
1350 b.ReadFastArray((char*) readOption.data(),nbig);
1351 if (obj) { // obj can be null if the class had a custom streamer and we do not have the shared library nor a streamerInfo.
1352 if (nch) {
1353 Add(obj,readOption.c_str());
1354 } else {
1355 Add(obj);
1356 }
1357 }
1358 }
1359 b.CheckByteCount(R__s, R__c,TList::IsA());
1360 return;
1361 }
1362
1363 // process old versions when TList::Streamer was in TCollection::Streamer
1364 if (v > 2)
1366 if (v > 1)
1367 fName.Streamer(b);
1368 b >> nobjects;
1369 for (Int_t i = 0; i < nobjects; i++) {
1370 b >> obj;
1371 Add(obj);
1372 }
1373 b.CheckByteCount(R__s, R__c,TList::IsA());
1374
1375 } else {
1377
1378 R__c = b.WriteVersion(TList::IsA(), kTRUE);
1380 fName.Streamer(b);
1381 nobjects = GetSize();
1382 b << nobjects;
1383
1384 TObjLink *lnk = fFirst.get();
1385 while (lnk) {
1386 obj = lnk->GetObject();
1387 b << obj;
1388
1389 nbig = strlen(lnk->GetAddOption());
1390 if (nbig > 254) {
1391 nch = 255;
1392 b << nch;
1393 b << nbig;
1394 } else {
1395 nch = UChar_t(nbig);
1396 b << nch;
1397 }
1398 b.WriteFastArray(lnk->GetAddOption(),nbig);
1399
1400 lnk = lnk->Next();
1401 }
1402 b.SetByteCount(R__c, kTRUE);
1403 }
1404}
#define b(i)
Definition RSha256.hxx:100
short Version_t
Class version identifier (short)
Definition RtypesCore.h:79
unsigned char UChar_t
Unsigned Character 1 byte (unsigned char)
Definition RtypesCore.h:52
constexpr Bool_t kFALSE
Definition RtypesCore.h:108
constexpr Bool_t kTRUE
Definition RtypesCore.h:107
const char Option_t
Option string (const char)
Definition RtypesCore.h:80
#define R__COLLECTION_READ_LOCKGUARD(mutex)
#define R__COLLECTION_WRITE_GUARD()
#define R__COLLECTION_READ_GUARD()
const Bool_t kIterForward
Definition TCollection.h:42
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define R__COLLECTION_ITER_GUARD(collection)
#define R__COLLECTION_WRITE_LOCKGUARD(mutex)
Option_t Option_t option
char name[80]
Definition TGX11.cxx:110
Buffer base class used for serializing objects.
Definition TBuffer.h:43
Bool_t IsArgNull(const char *where, const TObject *obj) const
Returns true if object is a null pointer.
const char * GetName() const override
Return name of this collection.
TString fName
Bool_t IsOwner() const
static void GarbageCollect(TObject *obj)
Add to the list of things to be cleaned up.
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
Iterator abstract base class.
Definition TIterator.h:30
Iterator of linked list.
Definition TList.h:196
Option_t * GetOption() const override
Returns the object option stored in the list.
Definition TList.cxx:1274
void Reset() override
Reset list iterator.
Definition TList.cxx:1291
const TList * fList
Definition TList.h:201
TObjLinkPtr_t fCursor
Definition TList.h:203
TObjLinkPtr_t fCurCursor
Definition TList.h:202
TObject * Next() override
Return next object in the list. Returns 0 when no more objects in list.
Definition TList.cxx:1243
TListIter()
Definition TList.h:207
TIterator & operator=(const TIterator &rhs) override
Overridden assignment operator.
Definition TList.cxx:1209
void SetOption(Option_t *option)
Sets the object option stored in the list.
Definition TList.cxx:1283
Bool_t fStarted
Definition TList.h:205
Bool_t operator!=(const TIterator &aIter) const override
This operator compares two TIterator objects.
Definition TList.cxx:1300
TClass * IsA() const override
Definition TList.h:233
Bool_t fDirection
Definition TList.h:204
A doubly linked list.
Definition TList.h:38
Bool_t LnkCompare(const TObjLinkPtr_t &l1, const TObjLinkPtr_t &l2)
Compares the objects stored in the TObjLink objects.
Definition TList.cxx:1102
void Streamer(TBuffer &) override
Stream all objects in the collection to or from the I/O buffer.
Definition TList.cxx:1323
void AddAfter(const TObject *after, TObject *obj) override
Insert object after object after in the list.
Definition TList.cxx:247
TObject * After(const TObject *obj) const override
Returns the object after object obj.
Definition TList.cxx:460
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:878
void Clear(Option_t *option="") override
Remove all objects from the list.
Definition TList.cxx:532
TObject ** GetObjectRef(const TObject *obj) const override
Return address of pointer to obj.
Definition TList.cxx:801
virtual ~TList()
Delete the list.
Definition TList.cxx:89
Bool_t fAscending
cache to speedup sequential calling of Before() and After() functions
Definition TList.h:49
void AddAt(TObject *obj, Int_t idx) override
Insert object at position idx in the list.
Definition TList.cxx:413
friend class TListIter
Definition TList.h:40
TObject * Before(const TObject *obj) const override
Returns the object before object obj.
Definition TList.cxx:501
TObject * FindObject(const char *name) const override
Find an object in this list using its name.
Definition TList.cxx:708
void RecursiveRemove(TObject *obj) override
Remove object from this collection and recursively remove the object from all other objects (and coll...
Definition TList.cxx:894
TObjLink * FindLink(const TObject *obj, Int_t &idx) const
Returns the TObjLink object that contains object obj.
Definition TList.cxx:758
void Add(TObject *obj) override
Definition TList.h:81
TObject * Remove(TObject *obj) override
Remove object from the list.
Definition TList.cxx:952
void AddLast(TObject *obj) override
Add object at the end of the list.
Definition TList.cxx:149
TObject * Last() const override
Return the last object in the list. Returns 0 when list is empty.
Definition TList.cxx:823
Bool_t IsAscending()
Definition TList.h:113
std::shared_ptr< TObjLink > TObjLinkPtr_t
Definition TList.h:43
TObject * First() const override
Return the first object in the list. Returns 0 when list is empty.
Definition TList.cxx:789
TObjLinkPtr_t fLast
pointer to first entry in linked list
Definition TList.h:47
void InsertAfter(const TObjLinkPtr_t &newlink, const TObjLinkPtr_t &prev)
Insert a new link in the chain.
Definition TList.cxx:1165
TIterator * MakeIterator(Bool_t dir=kIterForward) const override
Return a list iterator.
Definition TList.cxx:852
void AddBefore(const TObject *before, TObject *obj) override
Insert object before object before in the list.
Definition TList.cxx:193
TObjLink * LinkAt(Int_t idx) const
sorting order (when calling Sort() or for TSortedList)
Definition TList.cxx:835
virtual TObjLink * FirstLink() const
Definition TList.h:107
TObjLinkPtr_t NewLink(TObject *obj, const TObjLinkPtr_t &prev=nullptr)
Return a new TObjLink.
Definition TList.cxx:863
TObjLinkPtr_t fFirst
Definition TList.h:46
void Delete(Option_t *option="") override
Remove all objects from the list AND delete all heap based objects.
Definition TList.cxx:600
TObjLinkWeakPtr_t fCache
pointer to last entry in linked list
Definition TList.h:48
TClass * IsA() const override
Definition TList.h:115
TObject * At(Int_t idx) const override
Returns the object at position idx. Returns 0 if idx is out of range.
Definition TList.cxx:487
void RemoveLast() override
Remove the last object of the list.
Definition TList.cxx:1039
TObjLinkPtr_t * DoSort(TObjLinkPtr_t *head, Int_t n)
Sort linked list.
Definition TList.cxx:1114
void AddFirst(TObject *obj) override
Add object at the beginning of the list.
Definition TList.cxx:97
virtual void Sort(Bool_t order=kSortAscending)
Sort linked list.
Definition TList.cxx:1067
Mother of all ROOT objects.
Definition TObject.h:41
virtual void Streamer(TBuffer &)
Stream an object of class TObject.
Definition TObject.cxx:989
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1088
@ kCanDelete
if object in a list can be deleted
Definition TObject.h:68
virtual void Changed()
virtual void Streamer(TBuffer &)
Stream a string object.
Definition TString.cxx:1418
const Int_t n
Definition legend1.C:16
R__ALWAYS_INLINE bool HasBeenDeleted(const TObject *obj)
Check if the TObject's memory has been deleted.
Definition TObject.h:405
R__EXTERN TVirtualRWMutex * gCoreMutex
TMarker m
Definition textangle.C:8
TLine l
Definition textangle.C:4