#include "TList.h"
#include "TClass.h"
#include "TROOT.h"
#include "TVirtualMutex.h"
#include <string>
namespace std {} using namespace std;
ClassImp(TList)
TList::~TList()
{
Clear();
}
void TList::AddFirst(TObject *obj)
{
if (IsArgNull("AddFirst", obj)) return;
if (!fFirst) {
fFirst = NewLink(obj);
fLast = fFirst;
} else {
TObjLink *t = NewLink(obj);
t->fNext = fFirst;
fFirst->fPrev = t;
fFirst = t;
}
fSize++;
Changed();
}
void TList::AddFirst(TObject *obj, Option_t *opt)
{
if (IsArgNull("AddFirst", obj)) return;
if (!fFirst) {
fFirst = NewOptLink(obj, opt);
fLast = fFirst;
} else {
TObjLink *t = NewOptLink(obj, opt);
t->fNext = fFirst;
fFirst->fPrev = t;
fFirst = t;
}
fSize++;
Changed();
}
void TList::AddLast(TObject *obj)
{
if (IsArgNull("AddLast", obj)) return;
if (!fFirst) {
fFirst = NewLink(obj);
fLast = fFirst;
} else
fLast = NewLink(obj, fLast);
fSize++;
Changed();
}
void TList::AddLast(TObject *obj, Option_t *opt)
{
if (IsArgNull("AddLast", obj)) return;
if (!fFirst) {
fFirst = NewOptLink(obj, opt);
fLast = fFirst;
} else
fLast = NewOptLink(obj, opt, fLast);
fSize++;
Changed();
}
void TList::AddBefore(const TObject *before, TObject *obj)
{
if (IsArgNull("AddBefore", obj)) return;
if (!before)
TList::AddFirst(obj);
else {
Int_t idx;
TObjLink *t = FindLink(before, idx);
if (!t) {
Error("AddBefore", "before not found, object not added");
return;
}
if (t == fFirst)
TList::AddFirst(obj);
else {
NewLink(obj, t->Prev());
fSize++;
Changed();
}
}
}
void TList::AddBefore(TObjLink *before, TObject *obj)
{
if (IsArgNull("AddBefore", obj)) return;
if (!before)
TList::AddFirst(obj);
else {
if (before == fFirst)
TList::AddFirst(obj);
else {
NewLink(obj, before->Prev());
fSize++;
Changed();
}
}
}
void TList::AddAfter(const TObject *after, TObject *obj)
{
if (IsArgNull("AddAfter", obj)) return;
if (!after)
TList::AddLast(obj);
else {
Int_t idx;
TObjLink *t = FindLink(after, idx);
if (!t) {
Error("AddAfter", "after not found, object not added");
return;
}
if (t == fLast)
TList::AddLast(obj);
else {
NewLink(obj, t);
fSize++;
Changed();
}
}
}
void TList::AddAfter(TObjLink *after, TObject *obj)
{
if (IsArgNull("AddAfter", obj)) return;
if (!after)
TList::AddLast(obj);
else {
if (after == fLast)
TList::AddLast(obj);
else {
NewLink(obj, after);
fSize++;
Changed();
}
}
}
void TList::AddAt(TObject *obj, Int_t idx)
{
if (IsArgNull("AddAt", obj)) return;
TObjLink *lnk = LinkAt(idx);
if (!lnk)
TList::AddLast(obj);
else if (lnk == fFirst)
TList::AddFirst(obj);
else {
NewLink(obj, lnk->Prev());
fSize++;
Changed();
}
}
TObject *TList::After(const TObject *obj) const
{
TObjLink *t;
if (fCache && fCache->GetObject() && fCache->GetObject()->IsEqual(obj)) {
t = fCache;
((TList*)this)->fCache = fCache->Next();
} else {
Int_t idx;
t = FindLink(obj, idx);
if (t) ((TList*)this)->fCache = t->Next();
}
if (t && t->Next())
return t->Next()->GetObject();
else
return 0;
}
TObject *TList::At(Int_t idx) const
{
TObjLink *lnk = LinkAt(idx);
if (lnk) return lnk->GetObject();
return 0;
}
TObject *TList::Before(const TObject *obj) const
{
TObjLink *t;
if (fCache && fCache->GetObject() && fCache->GetObject()->IsEqual(obj)) {
t = fCache;
((TList*)this)->fCache = fCache->Prev();
} else {
Int_t idx;
t = FindLink(obj, idx);
if (t) ((TList*)this)->fCache = t->Prev();
}
if (t && t->Prev())
return t->Prev()->GetObject();
else
return 0;
}
void TList::Clear(Option_t *option)
{
Bool_t nodel = option ? (!strcmp(option, "nodelete") ? kTRUE : kFALSE) : kFALSE;
if (!nodel && IsOwner()) {
Delete(option);
return;
}
bool needRegister = fFirst && TROOT::Initialized();
if(needRegister) {
R__LOCKGUARD2(gROOTMutex);
needRegister = needRegister && !gROOT->GetListOfCleanups()->FindObject(this);
}
if (needRegister) {
R__LOCKGUARD2(gROOTMutex);
gROOT->GetListOfCleanups()->Add(this);
}
while (fFirst) {
TObjLink *tlk = fFirst;
fFirst = fFirst->Next();
fSize--;
if (!nodel && tlk->GetObject() && tlk->GetObject()->IsOnHeap()) {
if (tlk->GetObject()->TestBit(kCanDelete)) {
if(tlk->GetObject()->TestBit(kNotDeleted)) {
TCollection::GarbageCollect(tlk->GetObject());
}
}
}
delete tlk;
}
if (needRegister) {
R__LOCKGUARD2(gROOTMutex);
ROOT::GetROOT()->GetListOfCleanups()->Remove(this);
}
fFirst = fLast = fCache = 0;
fSize = 0;
Changed();
}
void TList::Delete(Option_t *option)
{
Bool_t slow = option ? (!strcmp(option, "slow") ? kTRUE : kFALSE) : kFALSE;
TList removeDirectory;
if (slow) {
bool needRegister = fFirst && TROOT::Initialized();
if(needRegister) {
R__LOCKGUARD2(gROOTMutex);
needRegister = needRegister && !gROOT->GetListOfCleanups()->FindObject(this);
}
if (needRegister) {
R__LOCKGUARD2(gROOTMutex);
gROOT->GetListOfCleanups()->Add(this);
}
while (fFirst) {
TObjLink *tlk = fFirst;
fFirst = fFirst->Next();
fSize--;
if (tlk->GetObject() && tlk->GetObject()->IsOnHeap())
TCollection::GarbageCollect(tlk->GetObject());
else if (tlk->GetObject() && tlk->GetObject()->IsA()->GetDirectoryAutoAdd())
removeDirectory.Add(tlk->GetObject());
delete tlk;
}
if (needRegister) {
R__LOCKGUARD2(gROOTMutex);
ROOT::GetROOT()->GetListOfCleanups()->Remove(this);
}
fFirst = fLast = fCache = 0;
fSize = 0;
} else {
TObjLink *first = fFirst;
fFirst = fLast = fCache = 0;
fSize = 0;
while (first) {
TObjLink *tlk = first;
first = first->Next();
if (tlk->GetObject() && tlk->GetObject()->IsOnHeap())
TCollection::GarbageCollect(tlk->GetObject());
else if (tlk->GetObject() && tlk->GetObject()->IsA()->GetDirectoryAutoAdd())
removeDirectory.Add(tlk->GetObject());
delete tlk;
}
}
TIter iRemDir(&removeDirectory);
TObject* dirRem = 0;
while ((dirRem = iRemDir())) {
(*dirRem->IsA()->GetDirectoryAutoAdd())(dirRem, 0);
}
Changed();
}
void TList::DeleteLink(TObjLink *lnk)
{
lnk->fNext = lnk->fPrev = 0;
lnk->fObject = 0;
delete lnk;
}
TObject *TList::FindObject(const char *name) const
{
if (!name) return 0;
TObjLink *lnk = FirstLink();
while (lnk) {
TObject *obj = lnk->GetObject();
const char *objname = obj->GetName();
if (objname && !strcmp(name, objname)) return obj;
lnk = lnk->Next();
}
return 0;
}
TObject *TList::FindObject(const TObject *obj) const
{
TObjLink *lnk = FirstLink();
while (lnk) {
TObject *ob = lnk->GetObject();
if (ob->IsEqual(obj)) return ob;
lnk = lnk->Next();
}
return 0;
}
TObjLink *TList::FindLink(const TObject *obj, Int_t &idx) const
{
if (!fFirst) return 0;
TObject *object;
TObjLink *lnk = fFirst;
idx = 0;
while (lnk) {
object = lnk->GetObject();
if (object) {
if (object->TestBit(kNotDeleted)) {
if (object->IsEqual(obj)) return lnk;
}
}
lnk = lnk->Next();
idx++;
}
return 0;
}
TObject *TList::First() const
{
if (fFirst) return fFirst->GetObject();
return 0;
}
TObject **TList::GetObjectRef(const TObject *obj) const
{
TObjLink *lnk = FirstLink();
while (lnk) {
TObject *ob = lnk->GetObject();
if (ob->IsEqual(obj)) return lnk->GetObjectRef();
lnk = lnk->Next();
}
return 0;
}
TObject *TList::Last() const
{
if (fLast) return fLast->GetObject();
return 0;
}
TObjLink *TList::LinkAt(Int_t idx) const
{
Int_t i = 0;
TObjLink *lnk = fFirst;
while (i < idx && lnk) {
i++;
lnk = lnk->Next();
}
return lnk;
}
TIterator *TList::MakeIterator(Bool_t dir) const
{
return new TListIter(this, dir);
}
TObjLink *TList::NewLink(TObject *obj, TObjLink *prev)
{
if (prev)
return new TObjLink(obj, prev);
else
return new TObjLink(obj);
}
TObjLink *TList::NewOptLink(TObject *obj, Option_t *opt, TObjLink *prev)
{
if (prev)
return new TObjOptLink(obj, prev, opt);
else
return new TObjOptLink(obj, opt);
}
void TList::RecursiveRemove(TObject *obj)
{
if (!obj) return;
TObjLink *lnk = fFirst;
TObjLink *next = 0;
while (lnk) {
next = lnk->Next();
TObject *ob = lnk->GetObject();
if (ob->TestBit(kNotDeleted)) {
if (ob->IsEqual(obj)) {
if (lnk == fFirst) {
fFirst = next;
if (lnk == fLast)
fLast = fFirst;
else
fFirst->fPrev = 0;
DeleteLink(lnk);
} else if (lnk == fLast) {
fLast = lnk->Prev();
fLast->fNext = 0;
DeleteLink(lnk);
} else {
lnk->Prev()->fNext = next;
lnk->Next()->fPrev = lnk->Prev();
DeleteLink(lnk);
}
fSize--;
fCache = 0;
Changed();
} else
ob->RecursiveRemove(obj);
}
lnk = next;
}
}
TObject *TList::Remove(TObject *obj)
{
if (!obj) return 0;
Int_t idx;
TObjLink *lnk = FindLink(obj, idx);
if (!lnk) return 0;
TObject *ob = lnk->GetObject();
if (lnk == fFirst) {
fFirst = lnk->Next();
if (lnk == fLast)
fLast = fFirst;
else
fFirst->fPrev = 0;
DeleteLink(lnk);
} else if (lnk == fLast) {
fLast = lnk->Prev();
fLast->fNext = 0;
DeleteLink(lnk);
} else {
lnk->Prev()->fNext = lnk->Next();
lnk->Next()->fPrev = lnk->Prev();
DeleteLink(lnk);
}
fSize--;
fCache = 0;
Changed();
return ob;
}
TObject *TList::Remove(TObjLink *lnk)
{
if (!lnk) return 0;
TObject *obj = lnk->GetObject();
if (lnk == fFirst) {
fFirst = lnk->Next();
if (lnk == fLast)
fLast = fFirst;
else
fFirst->fPrev = 0;
DeleteLink(lnk);
} else if (lnk == fLast) {
fLast = lnk->Prev();
fLast->fNext = 0;
DeleteLink(lnk);
} else {
lnk->Prev()->fNext = lnk->Next();
lnk->Next()->fPrev = lnk->Prev();
DeleteLink(lnk);
}
fSize--;
fCache = 0;
Changed();
return obj;
}
void TList::RemoveLast()
{
TObjLink *lnk = fLast;
if (!lnk) return;
if (lnk == fFirst) {
fFirst = 0;
fLast = 0;
} else {
fLast = lnk->Prev();
fLast->fNext = 0;
}
DeleteLink(lnk);
fSize--;
fCache = 0;
Changed();
}
void TList::Sort(Bool_t order)
{
if (!fFirst) return;
fAscending = order;
if (!fFirst->GetObject()->IsSortable()) {
Error("Sort", "objects in list are not sortable");
return;
}
DoSort(&fFirst, fSize);
TObjLink *ol, *lnk = fFirst;
if (lnk) lnk->fPrev = 0;
while ((ol = lnk)) {
lnk = lnk->fNext;
if (lnk)
lnk->fPrev = ol;
else
fLast = ol;
}
fSorted = kTRUE;
}
Bool_t TList::LnkCompare(TObjLink *l1, TObjLink *l2)
{
Int_t cmp = l1->GetObject()->Compare(l2->GetObject());
if ((IsAscending() && cmp <=0) || (!IsAscending() && cmp > 0))
return kTRUE;
return kFALSE;
}
TObjLink **TList::DoSort(TObjLink **head, Int_t n)
{
TObjLink *p1, *p2, **h2, **t2;
switch (n) {
case 0:
return head;
case 1:
return &((*head)->fNext);
case 2:
p2 = (p1 = *head)->fNext;
if (LnkCompare(p1, p2)) return &(p2->fNext);
p1->fNext = (*head = p2)->fNext;
return &((p2->fNext = p1)->fNext);
}
int m;
n -= m = n / 2;
t2 = DoSort(h2 = DoSort(head, n), m);
if (LnkCompare((p1 = *head), (p2 = *h2))) {
do {
if (!--n) return *h2 = p2, t2;
} while (LnkCompare((p1 = *(head = &(p1->fNext))), p2));
}
while (1) {
*head = p2;
do {
if (!--m) return *h2 = *t2, *t2 = p1, h2;
} while (!LnkCompare(p1, (p2 = *(head = &(p2->fNext)))));
*head = p1;
do {
if (!--n) return *h2 = p2, t2;
} while (LnkCompare((p1 = *(head = &(p1->fNext))), p2));
}
}
TObjLink::TObjLink(TObject *obj, TObjLink *prev)
: fNext(prev->fNext), fPrev(prev), fObject(obj)
{
fPrev->fNext = this;
if (fNext) fNext->fPrev = this;
}
ClassImp(TListIter)
TListIter::TListIter(const TList *l, Bool_t dir)
: fList(l), fCurCursor(0), fCursor(0), fDirection(dir), fStarted(kFALSE)
{
}
TListIter::TListIter(const TListIter &iter) : TIterator(iter)
{
fList = iter.fList;
fCurCursor = iter.fCurCursor;
fCursor = iter.fCursor;
fDirection = iter.fDirection;
fStarted = iter.fStarted;
}
TIterator &TListIter::operator=(const TIterator &rhs)
{
if (this != &rhs && rhs.IsA() == TListIter::Class()) {
const TListIter &rhs1 = (const TListIter &)rhs;
fList = rhs1.fList;
fCurCursor = rhs1.fCurCursor;
fCursor = rhs1.fCursor;
fDirection = rhs1.fDirection;
fStarted = rhs1.fStarted;
}
return *this;
}
TListIter &TListIter::operator=(const TListIter &rhs)
{
if (this != &rhs) {
fList = rhs.fList;
fCurCursor = rhs.fCurCursor;
fCursor = rhs.fCursor;
fDirection = rhs.fDirection;
fStarted = rhs.fStarted;
}
return *this;
}
TObject *TListIter::Next()
{
if (!fList) return 0;
if (fDirection == kIterForward) {
if (!fStarted) {
fCursor = fList->fFirst;
fStarted = kTRUE;
}
fCurCursor = fCursor;
if (fCursor) fCursor = fCursor->Next();
} else {
if (!fStarted) {
fCursor = fList->fLast;
fStarted = kTRUE;
}
fCurCursor = fCursor;
if (fCursor) fCursor = fCursor->Prev();
}
if (fCurCursor) return fCurCursor->GetObject();
return 0;
}
Option_t *TListIter::GetOption() const
{
if (fCurCursor) return fCurCursor->GetOption();
return "";
}
void TListIter::SetOption(Option_t *option)
{
if (fCurCursor) fCurCursor->SetOption(option);
}
void TListIter::Reset()
{
fStarted = kFALSE;
}
Bool_t TListIter::operator!=(const TIterator &aIter) const
{
if (IsA() == aIter.IsA()) {
const TListIter &iter(dynamic_cast<const TListIter &>(aIter));
return (fCurCursor != iter.fCurCursor);
}
return false;
}
Bool_t TListIter::operator!=(const TListIter &aIter) const
{
return (fCurCursor != aIter.fCurCursor);
}
void TList::Streamer(TBuffer &b)
{
Int_t nobjects;
UChar_t nch;
Int_t nbig;
TObject *obj;
UInt_t R__s, R__c;
if (b.IsReading()) {
Clear();
Version_t v = b.ReadVersion(&R__s, &R__c);
if (v > 3) {
TObject::Streamer(b);
fName.Streamer(b);
b >> nobjects;
string readOption;
for (Int_t i = 0; i < nobjects; i++) {
b >> obj;
b >> nch;
if (v > 4 && nch == 255) {
b >> nbig;
} else {
nbig = nch;
}
readOption.resize(nbig,'\0');
b.ReadFastArray((char*) readOption.data(),nbig);
if (obj) {
if (nch) {
Add(obj,readOption.c_str());
} else {
Add(obj);
}
}
}
b.CheckByteCount(R__s, R__c,TList::IsA());
return;
}
if (v > 2)
TObject::Streamer(b);
if (v > 1)
fName.Streamer(b);
b >> nobjects;
for (Int_t i = 0; i < nobjects; i++) {
b >> obj;
Add(obj);
}
b.CheckByteCount(R__s, R__c,TList::IsA());
} else {
R__c = b.WriteVersion(TList::IsA(), kTRUE);
TObject::Streamer(b);
fName.Streamer(b);
nobjects = GetSize();
b << nobjects;
TObjLink *lnk = fFirst;
while (lnk) {
obj = lnk->GetObject();
b << obj;
nbig = strlen(lnk->GetAddOption());
if (nbig > 254) {
nch = 255;
b << nch;
b << nbig;
} else {
nch = UChar_t(nbig);
b << nch;
}
b.WriteFastArray(lnk->GetAddOption(),nbig);
lnk = lnk->Next();
}
b.SetByteCount(R__c, kTRUE);
}
}