/*
<img src=gif/tordcollection.gif>
*/
//End_Html
#include "TOrdCollection.h"
#include "TError.h"
ClassImp(TOrdCollection)
TOrdCollection::TOrdCollection(Int_t capacity)
{
if (capacity < 0) {
Warning("TOrdCollection", "capacity (%d) < 0", capacity);
capacity = kDefaultCapacity;
} else if (capacity == 0)
capacity = kDefaultCapacity;
Init(capacity);
}
TOrdCollection::~TOrdCollection()
{
if (IsOwner())
Delete();
TStorage::Dealloc(fCont);
fCont = 0;
fSize = 0;
}
void TOrdCollection::AddAt(TObject *obj, Int_t idx)
{
Int_t physIdx;
if (idx > fSize) idx = fSize;
if (fGapSize <= 0)
SetCapacity(GrowBy(TMath::Max(fCapacity, (int)kMinExpand)));
if (idx == fGapStart) {
physIdx = fGapStart;
fGapStart++;
} else {
physIdx = PhysIndex(idx);
if (physIdx < fGapStart) {
MoveGapTo(physIdx);
physIdx = fGapStart;
fGapStart++;
} else {
MoveGapTo(physIdx - fGapSize);
physIdx = fGapStart + fGapSize - 1;
}
}
R__ASSERT(physIdx >= 0 && physIdx < fCapacity);
fCont[physIdx] = obj;
fGapSize--;
fSize++;
Changed();
}
void TOrdCollection::AddFirst(TObject *obj)
{
AddAt(obj, 0);
}
void TOrdCollection::AddLast(TObject *obj)
{
AddAt(obj, fSize);
}
void TOrdCollection::AddBefore(const TObject *before, TObject *obj)
{
if (!before)
AddFirst(obj);
else {
Int_t idx = IndexOf(before);
if (idx == -1) {
Error("AddBefore", "before not found, object not added");
return;
}
if (idx == 0) {
AddFirst(obj);
return;
}
AddAt(obj, idx);
}
}
void TOrdCollection::AddAfter(const TObject *after, TObject *obj)
{
if (!after)
AddLast(obj);
else {
Int_t idx = IndexOf(after);
if (idx == -1) {
Error("AddAfter", "after not found, object not added");
return;
}
AddAt(obj, idx+1);
}
}
TObject *TOrdCollection::After(const TObject *obj) const
{
if (!obj) return 0;
Int_t idx = IndexOf(obj);
if (idx == -1 || idx == fSize-1) return 0;
return At(idx+1);
}
TObject *TOrdCollection::At(Int_t idx) const
{
if (IllegalIndex("At", idx)) return 0;
return fCont[PhysIndex(idx)];
}
TObject *TOrdCollection::Before(const TObject *obj) const
{
if (!obj) return 0;
Int_t idx = IndexOf(obj);
if (idx == -1 || idx == 0) return 0;
return At(idx-1);
}
void TOrdCollection::Clear(Option_t *)
{
if (IsOwner())
Delete();
else {
TStorage::Dealloc(fCont);
fCont = 0;
Init(fCapacity);
fSize = 0;
}
}
void TOrdCollection::Delete(Option_t *)
{
for (Int_t i = 0; i < fSize; i++) {
TObject *obj = At(i);
if (obj && obj->IsOnHeap())
TCollection::GarbageCollect(obj);
}
TStorage::Dealloc(fCont);
fCont = 0;
Init(fCapacity);
fSize = 0;
}
TObject *TOrdCollection::First() const
{
return At(0);
}
TObject **TOrdCollection::GetObjectRef(const TObject *obj) const
{
Int_t index = IndexOf(obj);
return &fCont[index];
}
TObject *TOrdCollection::Last() const
{
return At(fSize-1);
}
Bool_t TOrdCollection::IllegalIndex(const char *method, Int_t idx) const
{
if (idx < 0 || idx >= fSize) {
Error(method, "index error (= %d) < 0 or > Size() (= %d)", idx, fSize);
return kTRUE;
}
return kFALSE;
}
Int_t TOrdCollection::IndexOf(const TObject *obj) const
{
for (Int_t i = 0; i < GetSize(); i++)
if (fCont[PhysIndex(i)]->IsEqual(obj))
return i;
return -1;
}
void TOrdCollection::Init(Int_t capacity)
{
fCapacity = capacity;
fCont = (TObject**) TStorage::Alloc(fCapacity*sizeof(TObject*));
memset(fCont, 0, fCapacity*sizeof(TObject*));
fGapStart = 0;
fGapSize = capacity;
Changed();
}
TIterator *TOrdCollection::MakeIterator(Bool_t dir) const
{
return new TOrdCollectionIter(this, dir);
}
void TOrdCollection::MoveGapTo(Int_t start)
{
Int_t i;
R__ASSERT(start + fGapSize - 1 < fCapacity);
if (fGapSize <= 0) {
fGapStart = start;
return;
}
if (start < fGapStart) {
for (i = fGapStart - 1; i >= start; i--)
fCont[i + fGapSize] = fCont[i];
} else if (start > fGapStart) {
Int_t stop = start + fGapSize;
for (i = fGapStart + fGapSize; i < stop; i++)
fCont[i - fGapSize] = fCont[i];
}
fGapStart = start;
for (i = fGapStart; i < fGapStart + fGapSize; i++)
fCont[i] = 0;
}
void TOrdCollection::PutAt(TObject *obj, Int_t idx)
{
if (IllegalIndex("PutAt", idx)) return;
Int_t phx = PhysIndex(idx);
R__ASSERT(phx >= 0 && phx < fCapacity);
fCont[phx] = obj;
Changed();
}
TObject *TOrdCollection::RemoveAt(Int_t idx)
{
Int_t physIdx;
if (idx == fGapStart - 1 || idx == fGapStart) {
if (idx == fGapStart)
physIdx = fGapStart + fGapSize;
else
physIdx = --fGapStart;
} else {
physIdx = PhysIndex(idx);
if (physIdx < fGapStart) {
MoveGapTo(physIdx + 1);
physIdx = --fGapStart;
} else {
MoveGapTo(physIdx - fGapSize);
physIdx = fGapStart + fGapSize;
}
}
R__ASSERT(physIdx >= 0 && physIdx < fCapacity);
TObject *obj = fCont[physIdx];
fCont[physIdx] = 0;
fGapSize++;
fSize--;
Changed();
if (LowWaterMark()) {
Int_t newCapacity = TMath::Max(int(fCapacity / kShrinkFactor), 1);
if (fCapacity > newCapacity)
SetCapacity(newCapacity);
}
return obj;
}
TObject *TOrdCollection::Remove(TObject *obj)
{
if (!obj) return 0;
Int_t idx = IndexOf(obj);
if (idx == -1) return 0;
return RemoveAt(idx);
}
void TOrdCollection::SetCapacity(Int_t newCapacity)
{
R__ASSERT(newCapacity > 0);
R__ASSERT(fSize <= newCapacity);
if (fCapacity == newCapacity) return;
Int_t newGapSize = newCapacity - fSize;
MoveGapTo(fCapacity - fGapSize);
fCont = (TObject**) TStorage::ReAlloc(fCont, newCapacity*sizeof(TObject*),
fCapacity*sizeof(TObject*));
fGapSize = newGapSize;
fCapacity = newCapacity;
}
void TOrdCollection::Sort()
{
if (fSize <= 0 || fSorted) return;
if (!At(0)->IsSortable()) {
Error("Sort", "objects in collection are not sortable");
return;
}
MoveGapTo(fCapacity - fGapSize);
QSort(fCont, 0, fSize);
fSorted = kTRUE;
}
Int_t TOrdCollection::BinarySearch(TObject *obj)
{
Int_t result;
if (!obj) return -1;
if (!fSorted) {
Error("BinarySearch", "collection must first be sorted");
return -1;
}
MoveGapTo(fCapacity - fGapSize);
Int_t base = 0;
Int_t last = base + GetSize() - 1;
while (last >= base) {
Int_t position = (base + last) / 2;
TObject *obj2 = fCont[position];
if ((obj2 == 0) || (result = obj->Compare(obj2)) == 0)
return LogIndex(position);
if (result < 0)
last = position - 1;
else
base = position + 1;
}
return -1;
}
ClassImp(TOrdCollectionIter)
TOrdCollectionIter::TOrdCollectionIter(const TOrdCollection *col, Bool_t dir): fCol(col), fDirection(dir)
{
Reset();
}
TOrdCollectionIter::TOrdCollectionIter(const TOrdCollectionIter &iter) : TIterator(iter)
{
fCol = iter.fCol;
fDirection = iter.fDirection;
fCursor = iter.fCursor;
fCurCursor = iter.fCurCursor;
}
TIterator &TOrdCollectionIter::operator=(const TIterator &rhs)
{
if (this != &rhs && rhs.IsA() == TOrdCollectionIter::Class()) {
const TOrdCollectionIter &rhs1 = (const TOrdCollectionIter &)rhs;
fCol = rhs1.fCol;
fDirection = rhs1.fDirection;
fCursor = rhs1.fCursor;
fCurCursor = rhs1.fCurCursor;
}
return *this;
}
TOrdCollectionIter &TOrdCollectionIter::operator=(const TOrdCollectionIter &rhs)
{
if (this != &rhs) {
fCol = rhs.fCol;
fDirection = rhs.fDirection;
fCursor = rhs.fCursor;
fCurCursor = rhs.fCurCursor;
}
return *this;
}
TObject *TOrdCollectionIter::Next()
{
fCurCursor = fCursor;
if (fDirection == kIterForward) {
if (fCursor < fCol->GetSize())
return fCol->At(fCursor++);
} else {
if (fCursor >= 0)
return fCol->At(fCursor--);
}
return 0;
}
void TOrdCollectionIter::Reset()
{
if (fDirection == kIterForward)
fCursor = 0;
else
fCursor = fCol->GetSize() - 1;
fCurCursor = fCursor;
}
bool TOrdCollectionIter::operator!=(const TIterator &aIter) const
{
if (nullptr == (&aIter))
return (fCurCursor < fCol->GetSize());
if (aIter.IsA() == TOrdCollectionIter::Class()) {
const TOrdCollectionIter &iter(dynamic_cast<const TOrdCollectionIter &>(aIter));
return (fCurCursor != iter.fCurCursor);
}
return false;
}
bool TOrdCollectionIter::operator!=(const TOrdCollectionIter &aIter) const
{
if (nullptr == (&aIter))
return (fCurCursor < fCol->GetSize());
return (fCurCursor != aIter.fCurCursor);
}
TObject *TOrdCollectionIter::operator*() const
{
return (((fCurCursor >= 0) && (fCurCursor < fCol->GetSize())) ?
fCol->At(fCurCursor) : nullptr);
}