Logo ROOT   6.16/01
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
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 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~~~
70Methods 2, 3 and 4 can also easily iterate backwards using either
71a backward TIter (using argument kIterBackward) or by using
72LastLink() 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>
81namespace 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
193void 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 }
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
247void 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
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
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
327TObject *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
368TObject *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
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
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
558void 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
574TObject *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
624TObjLink *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
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
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
980std::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
1025Wrapper around a TObject so it can be stored in a TList.
1026*/
1027
1028////////////////////////////////////////////////////////////////////////////////
1029/// Insert a new link in the chain.
1030
1031void 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
1041Iterator 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) {
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) {
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 }
1121 if (fCursor) {
1122 auto next = fCursor = fCursor->NextSP();
1123 }
1124 } else {
1125 if (!fStarted) {
1126 fCursor = fList->fLast;
1127 fStarted = kTRUE;
1128 }
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
1189void 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}
SVector< double, 2 > v
Definition: Dict.h:5
#define b(i)
Definition: RSha256.hxx:100
static double p1(double t, double a, double b)
static double p2(double t, double a, double b, double c)
int Int_t
Definition: RtypesCore.h:41
short Version_t
Definition: RtypesCore.h:61
unsigned char UChar_t
Definition: RtypesCore.h:34
unsigned int UInt_t
Definition: RtypesCore.h:42
const Bool_t kFALSE
Definition: RtypesCore.h:88
bool Bool_t
Definition: RtypesCore.h:59
const Bool_t kTRUE
Definition: RtypesCore.h:87
const char Option_t
Definition: RtypesCore.h:62
#define ClassImp(name)
Definition: Rtypes.h:363
#define R__COLLECTION_READ_LOCKGUARD(mutex)
Definition: TCollection.h:435
#define R__COLLECTION_WRITE_GUARD()
Definition: TCollection.h:125
#define R__COLLECTION_READ_GUARD()
Definition: TCollection.h:126
const Bool_t kIterForward
Definition: TCollection.h:40
#define R__COLLECTION_ITER_GUARD(collection)
Definition: TCollection.h:127
#define R__COLLECTION_WRITE_LOCKGUARD(mutex)
Definition: TCollection.h:438
Buffer base class used for serializing objects.
Definition: TBuffer.h:40
Bool_t IsArgNull(const char *where, const TObject *obj) const
Returns true if object is a null pointer.
virtual const char * GetName() const
Return name of this collection.
TString fName
Definition: TCollection.h:147
Bool_t IsOwner() const
Definition: TCollection.h:188
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.
Definition: TCollection.h:182
Iterator abstract base class.
Definition: TIterator.h:30
virtual TIterator & operator=(const TIterator &)
Definition: TIterator.h:37
Iterator of linked list.
Definition: TList.h:200
TObject * Next()
Return next object in the list. Returns 0 when no more objects in list.
Definition: TList.cxx:1109
const TList * fList
Definition: TList.h:205
TObjLinkPtr_t fCursor
Definition: TList.h:207
TObjLinkPtr_t fCurCursor
Definition: TList.h:206
void Reset()
Reset list iterator.
Definition: TList.cxx:1157
TListIter()
Definition: TList.h:211
void SetOption(Option_t *option)
Sets the object option stored in the list.
Definition: TList.cxx:1149
Bool_t fStarted
Definition: TList.h:209
Bool_t operator!=(const TIterator &aIter) const
This operator compares two TIterator objects.
Definition: TList.cxx:1166
TIterator & operator=(const TIterator &rhs)
Overridden assignment operator.
Definition: TList.cxx:1073
Option_t * GetOption() const
Returns the object option stored in the list.
Definition: TList.cxx:1140
Bool_t fDirection
Definition: TList.h:208
A doubly linked list.
Definition: TList.h:44
Bool_t LnkCompare(const TObjLinkPtr_t &l1, const TObjLinkPtr_t &l2)
Compares the objects stored in the TObjLink objects.
Definition: TList.cxx:968
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
virtual void Add(TObject *obj)
Definition: TList.h:87
virtual TObject * After(const TObject *obj) const
Returns the object after object obj.
Definition: TList.cxx:327
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:55
virtual TObject * Remove(TObject *obj)
Remove object from the list.
Definition: TList.cxx:818
virtual TObject ** GetObjectRef(const TObject *obj) const
Return address of pointer to obj.
Definition: TList.cxx:667
friend class TListIter
Definition: TList.h:46
virtual void AddAt(TObject *obj, Int_t idx)
Insert object at position idx in the list.
Definition: TList.cxx:303
TObjLink * FindLink(const TObject *obj, Int_t &idx) const
Returns the TObjLink object that contains object obj.
Definition: TList.cxx:624
Bool_t IsAscending()
Definition: TList.h:114
std::shared_ptr< TObjLink > TObjLinkPtr_t
Definition: TList.h:49
virtual void AddFirst(TObject *obj)
Add object at the beginning of the list.
Definition: TList.cxx:97
TObjLinkPtr_t fLast
pointer to first entry in linked list
Definition: TList.h:53
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
virtual TObject * FindObject(const char *name) const
Delete a TObjLink object.
Definition: TList.cxx:574
TObjLink * LinkAt(Int_t idx) const
sorting order (when calling Sort() or for TSortedList)
Definition: TList.cxx:701
virtual TObjLink * FirstLink() const
Definition: TList.h:108
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
TObjLinkPtr_t NewLink(TObject *obj, const TObjLinkPtr_t &prev=nullptr)
Return a new TObjLink.
Definition: TList.cxx:729
virtual TObject * Last() const
Return the last object in the list. Returns 0 when list is empty.
Definition: TList.cxx:689
virtual void AddAfter(const TObject *after, TObject *obj)
Insert object after object after in the list.
Definition: TList.cxx:247
TObjLinkPtr_t fFirst
Definition: TList.h:52
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 void AddBefore(const TObject *before, TObject *obj)
Insert object before object before in the list.
Definition: TList.cxx:193
virtual TIterator * MakeIterator(Bool_t dir=kIterForward) const
Return a list iterator.
Definition: TList.cxx:718
TObjLinkWeakPtr_t fCache
pointer to last entry in linked list
Definition: TList.h:54
virtual TObject * Before(const TObject *obj) const
Returns the object before object obj.
Definition: TList.cxx:368
virtual void Delete(Option_t *option="")
Remove all objects from the list AND delete all heap based objects.
Definition: TList.cxx:467
virtual TObject * First() const
Return the first object in the list. Returns 0 when list is empty.
Definition: TList.cxx:655
virtual void AddLast(TObject *obj)
Add object at the end of the list.
Definition: TList.cxx:149
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
virtual void Sort(Bool_t order=kSortAscending)
Sort linked list.
Definition: TList.cxx:933
Mother of all ROOT objects.
Definition: TObject.h:37
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
@ kNotDeleted
object has not been deleted
Definition: TObject.h:78
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition: TObject.h:172
virtual void RecursiveRemove(TObject *obj)
Recursively remove this object from a list.
Definition: TObject.cxx:572
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:880
@ kCanDelete
if object in a list can be deleted
Definition: TObject.h:58
virtual void Changed()
const Int_t n
Definition: legend1.C:16
R__EXTERN TVirtualRWMutex * gCoreMutex
Definition: first.py:1
STL namespace.
auto * m
Definition: textangle.C:8
auto * l
Definition: textangle.C:4