TOrdCollection.cxx

Go to the documentation of this file.
00001 // @(#)root/cont:$Id: TOrdCollection.cxx 23531 2008-04-24 16:23:42Z rdm $
00002 // Author: Fons Rademakers   13/09/95
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 //////////////////////////////////////////////////////////////////////////
00013 //                                                                      //
00014 // TOrdCollection                                                       //
00015 //                                                                      //
00016 // Ordered collection. An ordered collection has TList insertion        //
00017 // semantics but is implemented using an array of TObject*'s. It uses   //
00018 // less space than a TList (since there is no need for the prev and     //
00019 // next pointers), but it is more costly to insert objects (since it    //
00020 // has to create a gap by copying object pointers). TOrdCollection      //
00021 // is better than TList when objects are only added at the end of the   //
00022 // collection since no copying needs to be done.                        //
00023 //Begin_Html
00024 /*
00025 <img src=gif/tordcollection.gif>
00026 */
00027 //End_Html
00028 //                                                                      //
00029 //////////////////////////////////////////////////////////////////////////
00030 
00031 #include "TOrdCollection.h"
00032 #include "TError.h"
00033 
00034 
00035 ClassImp(TOrdCollection)
00036 
00037 //______________________________________________________________________________
00038 TOrdCollection::TOrdCollection(Int_t capacity)
00039 {
00040    // Create an ordered collection.
00041 
00042    if (capacity < 0) {
00043       Warning("TOrdCollection", "capacity (%d) < 0", capacity);
00044       capacity = kDefaultCapacity;
00045    } else if (capacity == 0)
00046       capacity = kDefaultCapacity;
00047    Init(capacity);
00048 }
00049 
00050 //______________________________________________________________________________
00051 TOrdCollection::~TOrdCollection()
00052 {
00053    // Delete the collection. Objects are not deleted unless the TOrdCollection
00054    // is the owner (set via SetOwner()).
00055 
00056    if (IsOwner())
00057       Delete();
00058 
00059    TStorage::Dealloc(fCont);
00060    fCont = 0;
00061    fSize = 0;
00062 }
00063 
00064 //______________________________________________________________________________
00065 void TOrdCollection::AddAt(TObject *obj, Int_t idx)
00066 {
00067    // Insert object at position idx in the collection.
00068 
00069    Int_t physIdx;
00070 
00071    if (idx > fSize) idx = fSize;
00072 
00073    if (fGapSize <= 0)
00074       SetCapacity(GrowBy(TMath::Max(fCapacity, (int)kMinExpand)));
00075 
00076    if (idx == fGapStart) {
00077       physIdx = fGapStart;
00078       fGapStart++;
00079    } else {
00080       physIdx = PhysIndex(idx);
00081       if (physIdx < fGapStart) {
00082          MoveGapTo(physIdx);
00083          physIdx = fGapStart;
00084          fGapStart++;
00085       } else {
00086          MoveGapTo(physIdx - fGapSize);
00087          physIdx = fGapStart + fGapSize - 1;
00088       }
00089    }
00090    R__ASSERT(physIdx >= 0 && physIdx < fCapacity);
00091    fCont[physIdx] = obj;
00092    fGapSize--;
00093    fSize++;
00094    Changed();
00095 }
00096 
00097 //______________________________________________________________________________
00098 void TOrdCollection::AddFirst(TObject *obj)
00099 {
00100    // Insert object at beginning of collection.
00101 
00102    AddAt(obj, 0);
00103 }
00104 
00105 //______________________________________________________________________________
00106 void TOrdCollection::AddLast(TObject *obj)
00107 {
00108    // Add object at the end of the collection.
00109 
00110    AddAt(obj, fSize);
00111 }
00112 
00113 //______________________________________________________________________________
00114 void TOrdCollection::AddBefore(const TObject *before, TObject *obj)
00115 {
00116    // Insert object before object before in the collection.
00117 
00118    if (!before)
00119       AddFirst(obj);
00120    else {
00121       Int_t idx = IndexOf(before);
00122       if (idx == -1) {
00123          Error("AddBefore", "before not found, object not added");
00124          return;
00125       }
00126       if (idx == 0) {
00127          AddFirst(obj);
00128          return;
00129       }
00130       AddAt(obj, idx);
00131    }
00132 }
00133 
00134 //______________________________________________________________________________
00135 void TOrdCollection::AddAfter(const TObject *after, TObject *obj)
00136 {
00137    // Insert object after object after in the collection.
00138 
00139    if (!after)
00140       AddLast(obj);
00141    else {
00142       Int_t idx = IndexOf(after);
00143       if (idx == -1) {
00144          Error("AddAfter", "after not found, object not added");
00145          return;
00146       }
00147       AddAt(obj, idx+1);
00148    }
00149 }
00150 
00151 //______________________________________________________________________________
00152 TObject *TOrdCollection::After(const TObject *obj) const
00153 {
00154    // Return the object after object obj. Returns 0 if obj is last
00155    // in collection.
00156 
00157    if (!obj) return 0;
00158 
00159    Int_t idx = IndexOf(obj);
00160    if (idx == -1 || idx == fSize-1) return 0;
00161 
00162    return At(idx+1);
00163 }
00164 
00165 //______________________________________________________________________________
00166 TObject *TOrdCollection::At(Int_t idx) const
00167 {
00168    // Returns the object at position idx. Returns 0 if idx is out of range.
00169 
00170    if (IllegalIndex("At", idx)) return 0;
00171    return fCont[PhysIndex(idx)];
00172 }
00173 
00174 //______________________________________________________________________________
00175 TObject *TOrdCollection::Before(const TObject *obj) const
00176 {
00177    // Returns the object before object obj. Returns 0 if obj is first
00178    // in collection.
00179 
00180    if (!obj) return 0;
00181 
00182    Int_t idx = IndexOf(obj);
00183    if (idx == -1 || idx == 0) return 0;
00184 
00185    return At(idx-1);
00186 }
00187 
00188 //______________________________________________________________________________
00189 void TOrdCollection::Clear(Option_t *)
00190 {
00191    // Remove all objects from the collection. Does not delete the objects
00192    // unless the TOrdCollection is the owner (set via SetOwner()).
00193 
00194    if (IsOwner())
00195       Delete();
00196    else {
00197       TStorage::Dealloc(fCont);
00198       fCont = 0;
00199       Init(fCapacity);
00200       fSize = 0;
00201    }
00202 }
00203 
00204 //______________________________________________________________________________
00205 void TOrdCollection::Delete(Option_t *)
00206 {
00207    // Remove all objects from the collection AND delete all heap based objects.
00208 
00209    for (Int_t i = 0; i < fSize; i++) {
00210       TObject *obj = At(i);
00211       if (obj && obj->IsOnHeap())
00212          TCollection::GarbageCollect(obj);
00213    }
00214    TStorage::Dealloc(fCont);
00215    fCont = 0;
00216    Init(fCapacity);
00217    fSize = 0;
00218 }
00219 
00220 //______________________________________________________________________________
00221 TObject *TOrdCollection::First() const
00222 {
00223    // Return the first object in the collection. Returns 0 when collection
00224    // is empty.
00225 
00226    return At(0);
00227 }
00228 
00229 //______________________________________________________________________________
00230 TObject **TOrdCollection::GetObjectRef(const TObject *obj) const
00231 {
00232    // return address of pointer obj
00233    Int_t index = IndexOf(obj);
00234    return &fCont[index];
00235 }
00236 
00237 //______________________________________________________________________________
00238 TObject *TOrdCollection::Last() const
00239 {
00240    // Return the last object in the collection. Returns 0 when collection
00241    // is empty.
00242 
00243    return At(fSize-1);
00244 }
00245 
00246 //______________________________________________________________________________
00247 Bool_t TOrdCollection::IllegalIndex(const char *method, Int_t idx) const
00248 {
00249    // Return true when index out of bounds and print error.
00250 
00251    if (idx < 0 || idx >= fSize) {
00252       Error(method, "index error (= %d) < 0 or > Size() (= %d)", idx, fSize);
00253       return kTRUE;
00254    }
00255    return kFALSE;
00256 }
00257 
00258 //______________________________________________________________________________
00259 Int_t TOrdCollection::IndexOf(const TObject *obj) const
00260 {
00261    // Return index of object in collection. Returns -1 when object not found.
00262    // Uses member IsEqual() to find object.
00263 
00264    for (Int_t i = 0; i < GetSize(); i++)
00265       if (fCont[PhysIndex(i)]->IsEqual(obj))
00266          return i;
00267 
00268    return -1;
00269 }
00270 
00271 //______________________________________________________________________________
00272 void TOrdCollection::Init(Int_t capacity)
00273 {
00274    // Initialize ordered collection.
00275 
00276    fCapacity = capacity;
00277    fCont = (TObject**) TStorage::Alloc(fCapacity*sizeof(TObject*)); //new TObject* [fCapacity];
00278    memset(fCont, 0, fCapacity*sizeof(TObject*));
00279    fGapStart = 0;
00280    fGapSize  = capacity;
00281    Changed();
00282 }
00283 
00284 //______________________________________________________________________________
00285 TIterator *TOrdCollection::MakeIterator(Bool_t dir) const
00286 {
00287    // Return an ordered collection iterator.
00288 
00289    return new TOrdCollectionIter(this, dir);
00290 }
00291 
00292 //______________________________________________________________________________
00293 void TOrdCollection::MoveGapTo(Int_t start)
00294 {
00295    // Move gap to new position. Gap needs to be moved when objects are
00296    // inserted not at the end.
00297 
00298    Int_t i;
00299 
00300    R__ASSERT(start + fGapSize - 1 < fCapacity);
00301 
00302    if (fGapSize <= 0) {
00303       fGapStart = start;
00304       return;
00305    }
00306    if (start < fGapStart) {
00307       for (i = fGapStart - 1; i >= start; i--)
00308          fCont[i + fGapSize] = fCont[i];
00309    } else if (start > fGapStart) {
00310       Int_t stop = start + fGapSize;
00311       for (i = fGapStart + fGapSize; i < stop; i++)
00312          fCont[i - fGapSize] = fCont[i];
00313    }
00314    fGapStart = start;
00315    for (i = fGapStart; i < fGapStart + fGapSize; i++)
00316       fCont[i] = 0;
00317 }
00318 
00319 //______________________________________________________________________________
00320 void TOrdCollection::PutAt(TObject *obj, Int_t idx)
00321 {
00322    // Put object at index idx. Overwrites what was at idx before.
00323 
00324    if (IllegalIndex("PutAt", idx)) return;
00325 
00326    Int_t phx = PhysIndex(idx);
00327    R__ASSERT(phx >= 0 && phx < fCapacity);
00328    fCont[phx] = obj;
00329    Changed();
00330 }
00331 
00332 //______________________________________________________________________________
00333 TObject *TOrdCollection::RemoveAt(Int_t idx)
00334 {
00335    // Remove object at index idx.
00336 
00337    Int_t physIdx;
00338 
00339    if (idx == fGapStart - 1 || idx == fGapStart) {
00340       if (idx == fGapStart)
00341          physIdx = fGapStart + fGapSize;        // at right boundary
00342       else
00343          physIdx = --fGapStart;                 // at left boundary
00344    } else {
00345       physIdx = PhysIndex(idx);
00346       if (physIdx < fGapStart) {
00347          MoveGapTo(physIdx + 1);
00348          physIdx = --fGapStart;
00349       } else {
00350          MoveGapTo(physIdx - fGapSize);
00351          physIdx = fGapStart + fGapSize;
00352       }
00353    }
00354    R__ASSERT(physIdx >= 0 && physIdx < fCapacity);
00355    TObject *obj = fCont[physIdx];
00356    fCont[physIdx] = 0;
00357    fGapSize++;
00358    fSize--;
00359    Changed();
00360 
00361    if (LowWaterMark()) {
00362       Int_t newCapacity = TMath::Max(int(fCapacity / kShrinkFactor), 1);
00363       if (fCapacity > newCapacity)
00364          SetCapacity(newCapacity);
00365    }
00366    return obj;
00367 }
00368 
00369 //______________________________________________________________________________
00370 TObject *TOrdCollection::Remove(TObject *obj)
00371 {
00372    // Remove object from collection.
00373 
00374    if (!obj) return 0;
00375 
00376    Int_t idx = IndexOf(obj);
00377    if (idx == -1) return 0;
00378 
00379    return RemoveAt(idx);
00380 }
00381 
00382 //______________________________________________________________________________
00383 void TOrdCollection::SetCapacity(Int_t newCapacity)
00384 {
00385    // Set/change ordered collection capacity.
00386 
00387    R__ASSERT(newCapacity > 0);
00388    R__ASSERT(fSize <= newCapacity);
00389 
00390    if (fCapacity == newCapacity) return;
00391 
00392    Int_t newGapSize = newCapacity - fSize;
00393    MoveGapTo(fCapacity - fGapSize);
00394    fCont = (TObject**) TStorage::ReAlloc(fCont, newCapacity*sizeof(TObject*),
00395                                          fCapacity*sizeof(TObject*));
00396    fGapSize  = newGapSize;
00397    fCapacity = newCapacity;
00398 }
00399 
00400 //______________________________________________________________________________
00401 void TOrdCollection::Sort()
00402 {
00403    // If objects in collection are sortable (i.e. IsSortable() returns true
00404    // for all objects) then sort collection.
00405 
00406    if (fSize <= 0 || fSorted) return;
00407    if (!At(0)->IsSortable()) {
00408       Error("Sort", "objects in collection are not sortable");
00409       return;
00410    }
00411 
00412    MoveGapTo(fCapacity - fGapSize);
00413    QSort(fCont, 0, fSize);
00414 
00415    fSorted = kTRUE;
00416 }
00417 
00418 //______________________________________________________________________________
00419 Int_t TOrdCollection::BinarySearch(TObject *obj)
00420 {
00421    // Find object using a binary search. Collection must first have been
00422    // sorted.
00423 
00424    Int_t result;
00425 
00426    if (!obj) return -1;
00427 
00428    if (!fSorted) {
00429       Error("BinarySearch", "collection must first be sorted");
00430       return -1;
00431    }
00432 
00433    MoveGapTo(fCapacity - fGapSize);
00434 
00435    Int_t base = 0;
00436    Int_t last = base + GetSize() - 1;
00437    while (last >= base) {
00438       Int_t position = (base + last) / 2;
00439       TObject *obj2 = fCont[position];
00440       if ((obj2 == 0) || (result = obj->Compare(obj2)) == 0)
00441          return LogIndex(position);
00442       if (result < 0)
00443          last = position - 1;
00444       else
00445          base = position + 1;
00446    }
00447    return -1;
00448 }
00449 
00450 
00451 //////////////////////////////////////////////////////////////////////////
00452 //                                                                      //
00453 // TOrdCollectionIter                                                   //
00454 //                                                                      //
00455 // Iterator of ordered collection.                                      //
00456 //                                                                      //
00457 //////////////////////////////////////////////////////////////////////////
00458 
00459 ClassImp(TOrdCollectionIter)
00460 
00461 //______________________________________________________________________________
00462 TOrdCollectionIter::TOrdCollectionIter(const TOrdCollection *col, Bool_t dir): fCol(col), fDirection(dir)
00463 {
00464    // Create collection iterator. By default the iteration direction
00465    // is kIterForward. To go backward use kIterBackward.
00466 
00467    Reset();
00468 }
00469 
00470 //______________________________________________________________________________
00471 TOrdCollectionIter::TOrdCollectionIter(const TOrdCollectionIter &iter) : TIterator(iter)
00472 {
00473    // Copy ctor.
00474 
00475    fCol       = iter.fCol;
00476    fDirection = iter.fDirection;
00477    fCursor    = iter.fCursor;
00478    fCurCursor = iter.fCurCursor;
00479 }
00480 
00481 //______________________________________________________________________________
00482 TIterator &TOrdCollectionIter::operator=(const TIterator &rhs)
00483 {
00484    // Overridden assignment operator.
00485 
00486    if (this != &rhs && rhs.IsA() == TOrdCollectionIter::Class()) {
00487       const TOrdCollectionIter &rhs1 = (const TOrdCollectionIter &)rhs;
00488       fCol       = rhs1.fCol;
00489       fDirection = rhs1.fDirection;
00490       fCursor    = rhs1.fCursor;
00491       fCurCursor = rhs1.fCurCursor;
00492    }
00493    return *this;
00494 }
00495 
00496 //______________________________________________________________________________
00497 TOrdCollectionIter &TOrdCollectionIter::operator=(const TOrdCollectionIter &rhs)
00498 {
00499    // Overloaded assignment operator.
00500 
00501    if (this != &rhs) {
00502       fCol       = rhs.fCol;
00503       fDirection = rhs.fDirection;
00504       fCursor    = rhs.fCursor;
00505       fCurCursor = rhs.fCurCursor;
00506    }
00507    return *this;
00508 }
00509 
00510 //______________________________________________________________________________
00511 TObject *TOrdCollectionIter::Next()
00512 {
00513    // Return next object in collection. Returns 0 when no more objects in
00514    // collection.
00515 
00516    fCurCursor = fCursor;
00517    if (fDirection == kIterForward) {
00518       if (fCursor < fCol->GetSize())
00519          return fCol->At(fCursor++);
00520    } else {
00521       if (fCursor >= 0)
00522          return fCol->At(fCursor--);
00523    }
00524    return 0;
00525 }
00526 
00527 //______________________________________________________________________________
00528 void TOrdCollectionIter::Reset()
00529 {
00530    // Reset collection iterator.
00531 
00532    if (fDirection == kIterForward)
00533       fCursor = 0;
00534    else
00535       fCursor = fCol->GetSize() - 1;
00536    
00537    fCurCursor = fCursor;
00538 }
00539 
00540 //______________________________________________________________________________
00541 bool TOrdCollectionIter::operator!=(const TIterator &aIter) const
00542 {
00543    // This operator compares two TIterator objects.
00544 
00545    if (nullptr == (&aIter))
00546       return (fCurCursor < fCol->GetSize());
00547 
00548    if (aIter.IsA() == TOrdCollectionIter::Class()) {
00549       const TOrdCollectionIter &iter(dynamic_cast<const TOrdCollectionIter &>(aIter));
00550       return (fCurCursor != iter.fCurCursor);
00551    }
00552    return false; // for base class we don't implement a comparison
00553 }
00554 
00555 //______________________________________________________________________________
00556 bool TOrdCollectionIter::operator!=(const TOrdCollectionIter &aIter) const
00557 {
00558    // This operator compares two TOrdCollectionIter objects.
00559 
00560    if (nullptr == (&aIter))
00561       return (fCurCursor < fCol->GetSize());
00562 
00563    return (fCurCursor != aIter.fCurCursor);
00564 }
00565 
00566 //______________________________________________________________________________
00567 TObject *TOrdCollectionIter::operator*() const
00568 {
00569    // Return current object or nullptr.
00570 
00571    return (((fCurCursor >= 0) && (fCurCursor < fCol->GetSize())) ?
00572            fCol->At(fCurCursor) : nullptr);
00573 }

Generated on Tue Jul 5 14:11:37 2011 for ROOT_528-00b_version by  doxygen 1.5.1