TClonesArray.cxx

Go to the documentation of this file.
00001 // @(#)root/cont:$Id: TClonesArray.cxx 37360 2010-12-07 08:09:27Z rdm $
00002 // Author: Rene Brun   11/02/96
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 // An array of clone (identical) objects. Memory for the objects        //
00015 // stored in the array is allocated only once in the lifetime of the    //
00016 // clones array. All objects must be of the same class. For the rest    //
00017 // this class has the same properties as TObjArray.                     //
00018 //                                                                      //
00019 // To reduce the very large number of new and delete calls in large     //
00020 // loops like this (O(100000) x O(10000) times new/delete):             //
00021 //                                                                      //
00022 //   TObjArray a(10000);                                                //
00023 //   while (TEvent *ev = (TEvent *)next()) {      // O(100000) events   //
00024 //      for (int i = 0; i < ev->Ntracks; i++) {   // O(10000) tracks    //
00025 //         a[i] = new TTrack(x,y,z,...);                                //
00026 //         ...                                                          //
00027 //         ...                                                          //
00028 //      }                                                               //
00029 //      ...                                                             //
00030 //      a.Delete();                                                     //
00031 //   }                                                                  //
00032 //                                                                      //
00033 // One better uses a TClonesArray which reduces the number of           //
00034 // new/delete calls to only O(10000):                                   //
00035 //                                                                      //
00036 //   TClonesArray a("TTrack", 10000);                                   //
00037 //   while (TEvent *ev = (TEvent *)next()) {      // O(100000) events   //
00038 //      for (int i = 0; i < ev->Ntracks; i++) {   // O(10000) tracks    //
00039 //         new(a[i]) TTrack(x,y,z,...);                                 //
00040 //         ...                                                          //
00041 //         ...                                                          //
00042 //      }                                                               //
00043 //      ...                                                             //
00044 //      a.Delete();                                                     //
00045 //   }                                                                  //
00046 //                                                                      //
00047 // Note: the only supported way to add objects to a TClonesArray is     //
00048 // via the new with placement method. The diffrent Add() methods of     //
00049 // TObjArray and its base classes are not allowed.                      //
00050 //                                                                      //
00051 // Considering that a new/delete costs about 70 mus on a 300 MHz HP,    //
00052 // O(10^9) new/deletes will save about 19 hours.                        //
00053 //                                                                      //
00054 //  NOTE 1
00055 //  ======
00056 // C/C++ offer the possibility to allocate and delete memory.
00057 // Forgetting to delete allocated memory is a programming error that originate "leaks",
00058 // i.e. the memory of your process grows and eventually your program crashes.
00059 // Even if you *always* delete the allocated memory, the recovered space may not be
00060 // efficiently reused. The process knows that there are portions of free memory,
00061 // but when you allocate it again, a fresh piece of memory is grabbed.
00062 // Your program is free from semantic errors, but the total memory of your process
00063 // still grows. Moreover your program's memory is full of "holes" which reduce the
00064 // efficiency of memory access, this is called "memory fragmentation".
00065 // Moreover new / delete are expensive operations in terms of CPU time.
00066 //
00067 // Without entering into technical details, the TClonesArray allow to "reuse" the
00068 // same portion of memory for new/delete avoiding memory fragmentation and memory
00069 // growth and improving by orders of magnitude the performance. Every time the
00070 // memory of the TClonesArray has to be reused, the Clear() method is employed.
00071 // To provide its benefits, each TClonesArray must be allocated *once* per process
00072 // and disposed of (deleted) *only when not needed any more*.
00073 // So a job should see *only one* deletion for each TClonesArray, which should be
00074 // "Cleared()" in between several times. Keep deleting a TClonesArray is a double
00075 // waste. Not only you do not avoid memory fragmentation, but you worsen it because
00076 // the TClonesArray itself is a rather heavy structure, and there is quite some
00077 // code in the destructor, so you have more memory fragmentation and slower code.
00078 //
00079 //  NOTE 2
00080 //  ======
00081 //
00082 // When investigating misuse of TClonesArray, please make sure of the following:
00083 //
00084 //    * Use Clear() or Clear("C") instead of Delete(). This will improve program
00085 //      execution time.
00086 //    * TClonesArray object classes containing pointers allocate memory.
00087 //      To avoid causing memory leaks, special Clear("C") must be used for
00088 //      clearing TClonesArray. When option "C" is specified, ROOT automatically
00089 //      executes the Clear() method (by default it is empty contained in TObject).
00090 //      This method must be overridden in the relevant TClonesArray object class,
00091 //      implementing the reset procedure for pointer objects.
00092 //    * To reduce memory fragmentation, please make sure that the TClonesArrays
00093 //      are not destroyed and created on every event.
00094 //      They must only be constructed/destructed at the beginning/end of the run.
00095 //////////////////////////////////////////////////////////////////////////
00096 
00097 #include <stdlib.h>
00098 #include "TClonesArray.h"
00099 #include "TError.h"
00100 #include "TROOT.h"
00101 #include "TClass.h"
00102 #include "TObjectTable.h"
00103 
00104 
00105 ClassImp(TClonesArray)
00106 
00107 //______________________________________________________________________________
00108 TClonesArray::TClonesArray() : TObjArray()
00109 {
00110    // Default Constructor.
00111 
00112    fClass      = 0;
00113    fKeep       = 0;
00114 }
00115 
00116 //______________________________________________________________________________
00117 TClonesArray::TClonesArray(const char *classname, Int_t s, Bool_t) : TObjArray(s)
00118 {
00119    // Create an array of clone objects of classname. The class must inherit from
00120    // TObject. If the class defines its own operator delete(), make sure that
00121    // it looks like this:
00122    //
00123    //    void MyClass::operator delete(void *vp)
00124    //    {
00125    //       if ((Long_t) vp != TObject::GetDtorOnly())
00126    //          ::operator delete(vp);       // delete space
00127    //       else
00128    //          TObject::SetDtorOnly(0);
00129    //    }
00130    //
00131    // The second argument s indicates an approximate number of objects
00132    // that will be entered in the array. If more than s objects are entered,
00133    // the array will be automatically expanded.
00134    //
00135    // The third argument is not used anymore and only there for backward
00136    // compatibility reasons.
00137 
00138    fKeep = 0;
00139    SetClass(classname,s);
00140 }
00141 
00142 //______________________________________________________________________________
00143 TClonesArray::TClonesArray(const TClass *cl, Int_t s, Bool_t) : TObjArray(s)
00144 {
00145    // Create an array of clone objects of class cl. The class must inherit from
00146    // TObject. If the class defines an own operator delete(), make sure that
00147    // it looks like this:
00148    //
00149    //    void MyClass::operator delete(void *vp)
00150    //    {
00151    //       if ((Long_t) vp != TObject::GetDtorOnly())
00152    //          ::operator delete(vp);       // delete space
00153    //       else
00154    //          TObject::SetDtorOnly(0);
00155    //    }
00156    //
00157    // The second argument, s, indicates an approximate number of objects
00158    // that will be entered in the array. If more than s objects are entered,
00159    // the array will be automatically expanded.
00160    //
00161    // The third argument is not used anymore and only there for backward
00162    // compatibility reasons.
00163 
00164    fKeep = 0;
00165    SetClass(cl,s);
00166 }
00167 
00168 //______________________________________________________________________________
00169 TClonesArray::TClonesArray(const TClonesArray& tc): TObjArray(tc)
00170 {
00171    // Copy ctor.
00172 
00173    fKeep = new TObjArray(tc.fSize);
00174    fClass = tc.fClass;
00175 
00176    BypassStreamer(kTRUE);
00177 
00178    for (Int_t i = 0; i < fSize; i++) {
00179       if (tc.fCont[i]) fCont[i] = tc.fCont[i]->Clone();
00180       fKeep->fCont[i] = fCont[i];
00181    }
00182 }
00183 
00184 //______________________________________________________________________________
00185 TClonesArray& TClonesArray::operator=(const TClonesArray& tc)
00186 {
00187    // Assignment operator.
00188 
00189    if (this == &tc) return *this;
00190 
00191    if (fClass != tc.fClass) {
00192       Error("operator=", "cannot copy TClonesArray's when classes are different");
00193       return *this;
00194    }
00195 
00196    if (tc.fSize > fSize)
00197       Expand(TMath::Max(tc.fSize, GrowBy(fSize)));
00198 
00199    Int_t i;
00200 
00201    for (i = 0; i < fSize; i++)
00202       if (fKeep->fCont[i]) {
00203          if (TObject::GetObjectStat() && gObjectTable)
00204             gObjectTable->RemoveQuietly(fKeep->fCont[i]);
00205          ::operator delete(fKeep->fCont[i]);
00206          fKeep->fCont[i] = 0;
00207          fCont[i] = 0;
00208       }
00209 
00210    BypassStreamer(kTRUE);
00211 
00212    for (i = 0; i < tc.fSize; i++) {
00213       if (tc.fCont[i]) fKeep->fCont[i] = tc.fCont[i]->Clone();
00214       fCont[i] = fKeep->fCont[i];
00215    }
00216 
00217    fLast = tc.fSize - 1;
00218    Changed();
00219    return *this;
00220 }
00221 
00222 //______________________________________________________________________________
00223 TClonesArray::~TClonesArray()
00224 {
00225    // Delete a clones array.
00226 
00227    if (fKeep) {
00228       for (Int_t i = 0; i < fKeep->fSize; i++) {
00229          TObject* p = fKeep->fCont[i];
00230          if (p && p->TestBit(kNotDeleted)) {
00231             // -- The TObject destructor has not been called.
00232             fClass->Destructor(p);
00233             fKeep->fCont[i] = 0;
00234          } else {
00235             // -- The TObject destructor was called, just free memory.
00236             //
00237             // remove any possible entries from the ObjectTable
00238             if (TObject::GetObjectStat() && gObjectTable) {
00239                gObjectTable->RemoveQuietly(p);
00240             }
00241             ::operator delete(p);
00242             fKeep->fCont[i] = 0;
00243          }
00244       }
00245    }
00246    SafeDelete(fKeep);
00247 
00248    // Protect against erroneously setting of owner bit
00249    SetOwner(kFALSE);
00250 }
00251 
00252 //______________________________________________________________________________
00253 void TClonesArray::BypassStreamer(Bool_t bypass)
00254 {
00255    // When the kBypassStreamer bit is set, the automatically
00256    // generated Streamer can call directly TClass::WriteBuffer.
00257    // Bypassing the Streamer improves the performance when writing/reading
00258    // the objects in the TClonesArray. However there is a drawback:
00259    // When a TClonesArray is written with split=0 bypassing the Streamer,
00260    // the StreamerInfo of the class in the array being optimized,
00261    // one cannot use later the TClonesArray with split>0. For example,
00262    // there is a problem with the following scenario:
00263    //  1- A class Foo has a TClonesArray of Bar objects
00264    //  2- The Foo object is written with split=0 to Tree T1.
00265    //     In this case the StreamerInfo for the class Bar is created
00266    //     in optimized mode in such a way that data members of the same type
00267    //     are written as an array improving the I/O performance.
00268    //  3- In a new program, T1 is read and a new Tree T2 is created
00269    //     with the object Foo in split>1
00270    //  4- When the T2 branch is created, the StreamerInfo for the class Bar
00271    //     is created with no optimization (mandatory for the split mode).
00272    //     The optimized Bar StreamerInfo is going to be used to read
00273    //     the TClonesArray in T1. The result will be Bar objects with
00274    //     data member values not in the right sequence.
00275    // The solution to this problem is to call BypassStreamer(kFALSE)
00276    // for the TClonesArray. In this case, the normal Bar::Streamer function
00277    // will be called. The Bar::Streamer function works OK independently
00278    // if the Bar StreamerInfo had been generated in optimized mode or not.
00279 
00280    if (bypass)
00281       SetBit(kBypassStreamer);
00282    else
00283       ResetBit(kBypassStreamer);
00284 }
00285 
00286 //______________________________________________________________________________
00287 void TClonesArray::Compress()
00288 {
00289    // Remove empty slots from array.
00290 
00291    Int_t j = 0, je = 0;
00292 
00293    TObject **tmp = new TObject* [fSize];
00294 
00295    for (Int_t i = 0; i < fSize; i++) {
00296       if (fCont[i]) {
00297          fCont[j] = fCont[i];
00298          fKeep->fCont[j] = fKeep->fCont[i];
00299          j++;
00300       } else {
00301          tmp[je] = fKeep->fCont[i];
00302          je++;
00303       }
00304    }
00305 
00306    fLast = j - 1;
00307 
00308    Int_t jf = 0;
00309    for ( ; j < fSize; j++) {
00310       fCont[j] = 0;
00311       fKeep->fCont[j] = tmp[jf];
00312       jf++;
00313    }
00314 
00315    delete [] tmp;
00316 
00317    R__ASSERT(je == jf);
00318 }
00319 
00320 //______________________________________________________________________________
00321 void TClonesArray::Clear(Option_t *option)
00322 {
00323    // Clear the clones array. Only use this routine when your objects don't
00324    // allocate memory since it will not call the object dtors.
00325    // However, if the class in the TClonesArray implements the function
00326    // Clear(Option_t *option) and if option = "C" the function Clear()
00327    // is called for all objects in the array. In the function Clear(), one
00328    // can delete objects or dynamic arrays allocated in the class.
00329    // This procedure is much faster than calling TClonesArray::Delete().
00330    // When the option starts with "C+", eg "C+xyz" the objects in the array
00331    // are in turn cleared with the option "xyz"
00332 
00333    if (option && option[0] == 'C') {
00334       const char *cplus = strstr(option,"+");
00335       Int_t n = GetEntriesFast();
00336       for (Int_t i = 0; i < n; i++) {
00337          TObject *obj = UncheckedAt(i);
00338          if (obj) {
00339             if (cplus) obj->Clear(cplus+1);
00340             else obj->Clear();
00341          }
00342       }
00343    }
00344 
00345    // Protect against erroneously setting of owner bit
00346    SetOwner(kFALSE);
00347 
00348    TObjArray::Clear();
00349 }
00350 
00351 //______________________________________________________________________________
00352 void TClonesArray::Delete(Option_t *)
00353 {
00354    // Clear the clones array. Use this routine when your objects allocate
00355    // memory (e.g. objects inheriting from TNamed or containing TStrings
00356    // allocate memory). If not you better use Clear() since if is faster.
00357 
00358    Long_t dtoronly = TObject::GetDtorOnly();
00359    for (Int_t i = 0; i < fSize; i++) {
00360       if (fCont[i] && fCont[i]->TestBit(kNotDeleted)) {
00361          // Tell custom operator delete() not to delete space when
00362          // object fCont[i] is deleted. Only destructors are called
00363          // for this object.
00364          TObject::SetDtorOnly(fCont[i]);
00365          delete fCont[i];
00366       }
00367    }
00368    // Restore the state.
00369    TObject::SetDtorOnly((void*)dtoronly);
00370 
00371    // Protect against erroneously setting of owner bit.
00372    SetOwner(kFALSE);
00373 
00374    TObjArray::Clear();
00375 }
00376 
00377 //______________________________________________________________________________
00378 void TClonesArray::Expand(Int_t newSize)
00379 {
00380    // Expand or shrink the array to newSize elements.
00381 
00382    if (newSize < 0) {
00383       Error ("Expand", "newSize must be positive (%d)", newSize);
00384       return;
00385    }
00386    if (newSize == fSize)
00387       return;
00388    if (newSize < fSize) {
00389       // release allocated space in fKeep and set to 0 so
00390       // Expand() will shrink correctly
00391       for (int i = newSize; i < fSize; i++)
00392          if (fKeep->fCont[i]) {
00393             if (TObject::GetObjectStat() && gObjectTable)
00394                gObjectTable->RemoveQuietly(fKeep->fCont[i]);
00395             ::operator delete(fKeep->fCont[i]);
00396             fKeep->fCont[i] = 0;
00397          }
00398    }
00399 
00400    TObjArray::Expand(newSize);
00401    fKeep->Expand(newSize);
00402 }
00403 
00404 //______________________________________________________________________________
00405 void TClonesArray::ExpandCreate(Int_t n)
00406 {
00407    // Expand or shrink the array to n elements and create the clone
00408    // objects by calling their default ctor. If n is less than the current size
00409    // the array is shrinked and the allocated space is freed.
00410    // This routine is typically used to create a clonesarray into which
00411    // one can directly copy object data without going via the
00412    // "new (arr[i]) MyObj()" (i.e. the vtbl is already set correctly).
00413 
00414    if (n < 0) {
00415       Error("ExpandCreate", "n must be positive (%d)", n);
00416       return ;
00417    }
00418    if (n > fSize)
00419       Expand(TMath::Max(n, GrowBy(fSize)));
00420 
00421    Int_t i;
00422    for (i = 0; i < n; i++) {
00423       if (!fKeep->fCont[i]) {
00424          fKeep->fCont[i] = (TObject*)fClass->New();
00425       } else if (!fKeep->fCont[i]->TestBit(kNotDeleted)) {
00426          // The object has been delete (or never initilized)
00427          fClass->New(fKeep->fCont[i]);
00428       }
00429       fCont[i] = fKeep->fCont[i];
00430    }
00431 
00432    for (i = n; i < fSize; i++)
00433       if (fKeep->fCont[i]) {
00434          if (TObject::GetObjectStat() && gObjectTable)
00435             gObjectTable->RemoveQuietly(fKeep->fCont[i]);
00436          ::operator delete(fKeep->fCont[i]);
00437          fKeep->fCont[i] = 0;
00438          fCont[i] = 0;
00439       }
00440 
00441    fLast = n - 1;
00442    Changed();
00443 }
00444 
00445 //______________________________________________________________________________
00446 void TClonesArray::ExpandCreateFast(Int_t n)
00447 {
00448    // Expand or shrink the array to n elements and create the clone
00449    // objects by calling their default ctor. If n is less than the current size
00450    // the array is shrinked but the allocated space is _not_ freed.
00451    // This routine is typically used to create a clonesarray into which
00452    // one can directly copy object data without going via the
00453    // "new (arr[i]) MyObj()" (i.e. the vtbl is already set correctly).
00454    // This is a simplified version of ExpandCreate used in the TTree mechanism.
00455 
00456    if (n > fSize)
00457       Expand(TMath::Max(n, GrowBy(fSize)));
00458 
00459    Int_t i;
00460    for (i = 0; i < n; i++) {
00461       if (!fKeep->fCont[i]) {
00462          fKeep->fCont[i] = (TObject*)fClass->New();
00463       } else if (!fKeep->fCont[i]->TestBit(kNotDeleted)) {
00464          // The object has been delete (or never initilized)
00465          fClass->New(fKeep->fCont[i]);
00466       }
00467       fCont[i] = fKeep->fCont[i];
00468    }
00469    fLast = n - 1;
00470    Changed();
00471 }
00472 
00473 //______________________________________________________________________________
00474 TObject *TClonesArray::RemoveAt(Int_t idx)
00475 {
00476    // Remove object at index idx.
00477 
00478    if (!BoundsOk("RemoveAt", idx)) return 0;
00479 
00480    int i = idx-fLowerBound;
00481 
00482    if (fCont[i] && fCont[i]->TestBit(kNotDeleted)) {
00483       // Tell custom operator delete() not to delete space when
00484       // object fCont[i] is deleted. Only destructors are called
00485       // for this object.
00486       Long_t dtoronly = TObject::GetDtorOnly();
00487       TObject::SetDtorOnly(fCont[i]);
00488       delete fCont[i];
00489       TObject::SetDtorOnly((void*)dtoronly);
00490    }
00491 
00492    if (fCont[i]) {
00493       fCont[i] = 0;
00494       // recalculate array size
00495       if (i == fLast)
00496          do { fLast--; } while (fLast >= 0 && fCont[fLast] == 0);
00497       Changed();
00498    }
00499 
00500    return 0;
00501 }
00502 
00503 //______________________________________________________________________________
00504 TObject *TClonesArray::Remove(TObject *obj)
00505 {
00506    // Remove object from array.
00507 
00508    if (!obj) return 0;
00509 
00510    Int_t i = IndexOf(obj) - fLowerBound;
00511 
00512    if (i == -1) return 0;
00513 
00514    if (fCont[i] && fCont[i]->TestBit(kNotDeleted)) {
00515       // Tell custom operator delete() not to delete space when
00516       // object fCont[i] is deleted. Only destructors are called
00517       // for this object.
00518       Long_t dtoronly = TObject::GetDtorOnly();
00519       TObject::SetDtorOnly(fCont[i]);
00520       delete fCont[i];
00521       TObject::SetDtorOnly((void*)dtoronly);
00522    }
00523 
00524    fCont[i] = 0;
00525    // recalculate array size
00526    if (i == fLast)
00527       do { fLast--; } while (fLast >= 0 && fCont[fLast] == 0);
00528    Changed();
00529    return obj;
00530 }
00531 
00532 //______________________________________________________________________________
00533 void TClonesArray::RemoveRange(Int_t idx1, Int_t idx2)
00534 {
00535    // Remove objects from index idx1 to idx2 included.
00536 
00537    if (!BoundsOk("RemoveRange", idx1)) return;
00538    if (!BoundsOk("RemoveRange", idx2)) return;
00539 
00540    Long_t dtoronly = TObject::GetDtorOnly();
00541 
00542    idx1 -= fLowerBound;
00543    idx2 -= fLowerBound;
00544 
00545    Bool_t change = kFALSE;
00546    for (TObject **obj=fCont+idx1; obj<=fCont+idx2; obj++) {
00547       if (!*obj) continue;
00548       if ((*obj)->TestBit(kNotDeleted)) {
00549          // Tell custom operator delete() not to delete space when
00550          // object fCont[i] is deleted. Only destructors are called
00551          // for this object.
00552          TObject::SetDtorOnly(*obj);
00553          delete *obj;
00554       }
00555       *obj = 0;
00556       change = kTRUE;
00557    }
00558 
00559    TObject::SetDtorOnly((void*)dtoronly);
00560 
00561    // recalculate array size
00562    if (change) Changed();
00563    if (idx1 < fLast || fLast > idx2) return;
00564    do { fLast--; } while (fLast >= 0 && fCont[fLast] == 0);
00565 }
00566 
00567 //______________________________________________________________________________
00568 void TClonesArray::SetClass(const TClass *cl, Int_t s)
00569 {
00570    // Create an array of clone objects of class cl. The class must inherit from
00571    // TObject. If the class defines an own operator delete(), make sure that
00572    // it looks like this:
00573    //
00574    //    void MyClass::operator delete(void *vp)
00575    //    {
00576    //       if ((Long_t) vp != TObject::GetDtorOnly())
00577    //          ::operator delete(vp);       // delete space
00578    //       else
00579    //          TObject::SetDtorOnly(0);
00580    //    }
00581    //
00582    // The second argument s indicates an approximate number of objects
00583    // that will be entered in the array. If more than s objects are entered,
00584    // the array will be automatically expanded.
00585    //
00586    // NB: This function should not be called in the TClonesArray is already
00587    //     initialized with a class.
00588 
00589    if (fKeep) {
00590       Error("SetClass", "TClonesArray already initialized with another class");
00591       return;
00592    }
00593    fClass = (TClass*)cl;
00594    if (!fClass) {
00595       MakeZombie();
00596       Error("SetClass", "called with a null pointer");
00597       return;
00598    }
00599    const char *classname = fClass->GetName();
00600    if (!fClass->InheritsFrom(TObject::Class())) {
00601       MakeZombie();
00602       Error("SetClass", "%s does not inherit from TObject", classname);
00603       return;
00604    }
00605    Int_t nch = strlen(classname)+2;
00606    char *name = new char[nch];
00607    snprintf(name,nch, "%ss", classname);
00608    SetName(name);
00609    delete [] name;
00610 
00611    fKeep = new TObjArray(s);
00612 
00613    BypassStreamer(kTRUE);
00614 }
00615 
00616 //______________________________________________________________________________
00617 void TClonesArray::SetClass(const char *classname, Int_t s)
00618 {
00619    //see TClonesArray::SetClass(const TClass*)
00620 
00621    SetClass(TClass::GetClass(classname),s);
00622 }
00623 
00624 
00625 //______________________________________________________________________________
00626 void TClonesArray::SetOwner(Bool_t /* enable */)
00627 {
00628    // A TClonesArray is always the owner of the object it contains.
00629    // However the collection its inherits from (TObjArray) does not.
00630    // Hence this member function needs to be a nop for TClonesArray.
00631 
00632    // Nothing to be done.
00633 }
00634 
00635 //______________________________________________________________________________
00636 void TClonesArray::Sort(Int_t upto)
00637 {
00638    // If objects in array are sortable (i.e. IsSortable() returns true
00639    // for all objects) then sort array.
00640 
00641    Int_t nentries = GetAbsLast()+1;
00642    if (nentries <= 0 || fSorted) return;
00643    for (Int_t i = 0; i < fSize; i++)
00644       if (fCont[i]) {
00645          if (!fCont[i]->IsSortable()) {
00646             Error("Sort", "objects in array are not sortable");
00647             return;
00648          }
00649       }
00650 
00651    QSort(fCont, fKeep->fCont, 0, TMath::Min(nentries, upto-fLowerBound));
00652 
00653    fLast   = -2;
00654    fSorted = kTRUE;
00655 }
00656 
00657 //_______________________________________________________________________
00658 void TClonesArray::Streamer(TBuffer &b)
00659 {
00660    // Write all objects in array to the I/O buffer. ATTENTION: empty slots
00661    // are also stored (using one byte per slot). If you don't want this
00662    // use a TOrdCollection or TList.
00663 
00664    // Important Note: if you modify this function, remember to also modify
00665    // TConvertClonesArrayToProxy accordingly
00666 
00667    Int_t   nobjects;
00668    char    nch;
00669    TString s, classv;
00670    UInt_t R__s, R__c;
00671 
00672    if (b.IsReading()) {
00673       Version_t v = b.ReadVersion(&R__s, &R__c);
00674       if (v == 3) {
00675          const Int_t kOldBypassStreamer = BIT(14);
00676          if (TestBit(kOldBypassStreamer)) BypassStreamer();
00677       }
00678       if (v > 2)
00679          TObject::Streamer(b);
00680       if (v > 1)
00681          fName.Streamer(b);
00682       s.Streamer(b);
00683       classv = s;
00684       Int_t clv = 0;
00685       Ssiz_t pos = s.Index(";");
00686       if (pos != kNPOS) {
00687          classv = s(0, pos);
00688          s = s(pos+1, s.Length()-pos-1);
00689          clv = s.Atoi();
00690       }
00691       TClass *cl = TClass::GetClass(classv);
00692       if (!cl) {
00693          printf("TClonesArray::Streamer expecting class %s\n", classv.Data());
00694          b.CheckByteCount(R__s, R__c,TClonesArray::IsA());
00695          return;
00696       }
00697 
00698       b >> nobjects;
00699       if (nobjects < 0)
00700          nobjects = -nobjects;  // still there for backward compatibility
00701       b >> fLowerBound;
00702       if (fClass == 0 && fKeep == 0) {
00703          fClass = cl;
00704          fKeep  = new TObjArray(fSize);
00705          Expand(nobjects);
00706       }
00707       if (cl != fClass) {
00708          fClass = cl;
00709          //this case may happen when switching from an emulated class to the real class
00710          //may not be an error. fClass may point to a deleted object
00711          //Error("Streamer", "expecting objects of type %s, finding objects"
00712          //   " of type %s", fClass->GetName(), cl->GetName());
00713          //return;
00714       }
00715 
00716       // make sure there are enough slots in the fKeep array
00717       if (fKeep->GetSize() < nobjects)
00718          Expand(nobjects);
00719 
00720       //reset fLast. nobjects may be 0
00721       Int_t oldLast = fLast;
00722       fLast = nobjects-1;
00723 
00724       //TStreamerInfo *sinfo = fClass->GetStreamerInfo(clv);
00725       if (CanBypassStreamer() && !b.TestBit(TBuffer::kCannotHandleMemberWiseStreaming)) {
00726          for (Int_t i = 0; i < nobjects; i++) {
00727             if (!fKeep->fCont[i]) {
00728                fKeep->fCont[i] = (TObject*)fClass->New();
00729             } else if (!fKeep->fCont[i]->TestBit(kNotDeleted)) {
00730                // The object has been delete (or never initialized)
00731                fClass->New(fKeep->fCont[i]);
00732             }
00733 
00734             fCont[i] = fKeep->fCont[i];
00735          }
00736          //sinfo->ReadBufferClones(b,this,nobjects,-1,0);
00737          b.ReadClones(this,nobjects,clv);
00738 
00739       } else {
00740          for (Int_t i = 0; i < nobjects; i++) {
00741             b >> nch;
00742             if (nch) {
00743                if (!fKeep->fCont[i])
00744                   fKeep->fCont[i] = (TObject*)fClass->New();
00745                else if (!fKeep->fCont[i]->TestBit(kNotDeleted)) {
00746                   // The object has been deleted (or never initialized)
00747                   fClass->New(fKeep->fCont[i]);
00748                }
00749 
00750                fCont[i] = fKeep->fCont[i];
00751                b.StreamObject(fKeep->fCont[i]);
00752             }
00753          }
00754       }
00755       for (Int_t i = TMath::Max(nobjects,0); i < oldLast+1; ++i) fCont[i] = 0;
00756       Changed();
00757       b.CheckByteCount(R__s, R__c,TClonesArray::IsA());
00758    } else {
00759       //Make sure TStreamerInfo is not optimized, otherwise it will not be
00760       //possible to support schema evolution in read mode.
00761       //In case the StreamerInfo has already been computed and optimized,
00762       //one must disable the option BypassStreamer
00763       b.ForceWriteInfoClones(this);
00764 
00765       // make sure the status of bypass streamer is part of the buffer
00766       // (bits in TObject), so that when reading the object the right
00767       // mode is used, independent of the method (e.g. written via
00768       // TMessage, received and stored to a file and then later read via
00769       // TBufferFile)
00770       Bool_t bypass = kFALSE;
00771       if (b.TestBit(TBuffer::kCannotHandleMemberWiseStreaming)) {
00772          bypass = CanBypassStreamer();
00773          BypassStreamer(kFALSE);
00774       }
00775 
00776       R__c = b.WriteVersion(TClonesArray::IsA(), kTRUE);
00777       TObject::Streamer(b);
00778       fName.Streamer(b);
00779       s.Form("%s;%d", fClass->GetName(), fClass->GetClassVersion());
00780       s.Streamer(b);
00781       nobjects = GetEntriesFast();
00782       b << nobjects;
00783       b << fLowerBound;
00784       if (CanBypassStreamer()) {
00785          b.WriteClones(this,nobjects);
00786       } else {
00787          for (Int_t i = 0; i < nobjects; i++) {
00788             if (!fCont[i]) {
00789                nch = 0;
00790                b << nch;
00791             } else {
00792                nch = 1;
00793                b << nch;
00794                b.StreamObject(fCont[i]);
00795             }
00796          }
00797       }
00798       b.SetByteCount(R__c, kTRUE);
00799 
00800       if (bypass)
00801          BypassStreamer();
00802    }
00803 }
00804 
00805 //______________________________________________________________________________
00806 TObject *&TClonesArray::operator[](Int_t idx)
00807 {
00808    // Return pointer to reserved area in which a new object of clones
00809    // class can be constructed. This operator should not be used for
00810    // lefthand side assignments, like a[2] = xxx. Only like,
00811    // new (a[2]) myClass, or xxx = a[2]. Of course right hand side usage
00812    // is only legal after the object has been constructed via the
00813    // new operator or via the New() method. To remove elements from
00814    // the clones array use Remove() or RemoveAt().
00815 
00816    if (idx < 0) {
00817       Error("operator[]", "out of bounds at %d in %lx", idx, (Long_t)this);
00818       return fCont[0];
00819    }
00820    if (!fClass) {
00821       Error("operator[]", "invalid class specified in TClonesArray ctor");
00822       return fCont[0];
00823    }
00824    if (idx >= fSize)
00825       Expand(TMath::Max(idx+1, GrowBy(fSize)));
00826 
00827    if (!fKeep->fCont[idx])
00828       fKeep->fCont[idx] = (TObject*) TStorage::ObjectAlloc(fClass->Size());
00829 
00830    fCont[idx] = fKeep->fCont[idx];
00831 
00832    fLast = TMath::Max(idx, GetAbsLast());
00833    Changed();
00834 
00835    return fCont[idx];
00836 }
00837 
00838 //______________________________________________________________________________
00839 TObject *TClonesArray::operator[](Int_t idx) const
00840 {
00841    // Return the object at position idx. Returns 0 if idx is out of bounds.
00842 
00843    if (idx < 0 || idx >= fSize) {
00844       Error("operator[]", "out of bounds at %d in %lx", idx, (Long_t)this);
00845       return 0;
00846    }
00847 
00848    return fCont[idx];
00849 }
00850 
00851 //______________________________________________________________________________
00852 TObject *TClonesArray::New(Int_t idx)
00853 {
00854    // Create an object of type fClass with the default ctor at the specified
00855    // index. Returns 0 in case of error.
00856 
00857    if (idx < 0) {
00858       Error("New", "out of bounds at %d in %lx", idx, (Long_t)this);
00859       return 0;
00860    }
00861    if (!fClass) {
00862       Error("New", "invalid class specified in TClonesArray ctor");
00863       return 0;
00864    }
00865 
00866    return (TObject *)fClass->New(operator[](idx));
00867 }
00868 
00869 //______________________________________________________________________________
00870 //
00871 // The following functions are utilities implemented by Jason Detwiler
00872 // (jadetwiler@lbl.gov)
00873 //
00874 //______________________________________________________________________________
00875 void TClonesArray::AbsorbObjects(TClonesArray* tc)
00876 {
00877    // Directly move the object pointers from tc to this without cloning
00878    // (copying).
00879    // "this" takes over ownership of all of tc's object pointers. tc is left
00880    // empty upon return
00881 
00882    // tests
00883    if(tc == NULL || tc == this || tc->GetEntriesFast() == 0) return;
00884    if (fClass != tc->fClass) {
00885       Error("AbsorbObjects", "cannot absorb objects when classes are different");
00886       return;
00887    }
00888 
00889    // cache the sorted status
00890    bool wasSorted = IsSorted() && tc->IsSorted() &&
00891                     (Last() == NULL || Last()->Compare(tc->First()) == -1);
00892 
00893    // expand this
00894    Int_t oldSize = GetEntriesFast();
00895    Int_t newSize = oldSize + tc->GetEntriesFast();
00896    if(newSize > fSize) Expand(newSize);
00897 
00898    // move
00899    for(Int_t i = 0; i <= tc->GetEntriesFast(); i++) {
00900       fCont[oldSize+i] = tc->fCont[i];
00901       (*fKeep)[oldSize+i] = (*(tc->fKeep))[i];
00902       tc->fCont[i] = NULL;
00903       (*(tc->fKeep))[i] = NULL;
00904    }
00905 
00906    // cleanup
00907    fLast = newSize-1;
00908    tc->fLast = -1;
00909    if(!wasSorted) Changed();
00910 }
00911 
00912 
00913 //______________________________________________________________________________
00914 void TClonesArray::MultiSort(Int_t nTCs, TClonesArray** tcs, Int_t upto)
00915 {
00916    // Sort multiple TClonesArrays simultaneously with this.
00917    // If objects in array are sortable (i.e. IsSortable() returns true
00918    // for all objects) then sort array.
00919 
00920    Int_t nentries = GetAbsLast()+1;
00921    if (nentries <= 1 || fSorted) return;
00922    bool sortedCheck = true;
00923    for (Int_t i = 0; i < fSize; i++) {
00924       if (fCont[i]) {
00925          if (!fCont[i]->IsSortable()) {
00926             Error("MultiSort", "objects in array are not sortable");
00927             return;
00928          }
00929       }
00930       if (sortedCheck && i > 1) {
00931          if(ObjCompare(fCont[i], fCont[i-1]) < 0) sortedCheck = false;
00932       }
00933    }
00934    if (sortedCheck) {
00935       fSorted = true;
00936       return;
00937    }
00938 
00939    for (int i=0; i<nTCs; i++) {
00940       if (tcs[i] == this) {
00941          Error("MultiSort", "tcs[%d] = \"this\"", i);
00942          return;
00943       }
00944       if (tcs[i]->GetEntriesFast() != GetEntriesFast()) {
00945          Error("MultiSort", "tcs[%d] has length %d != length of this (%d)",
00946                i, tcs[i]->GetEntriesFast(), this->GetEntriesFast());
00947          return;
00948       }
00949    }
00950 
00951    int nBs = nTCs*2+1;
00952    TObject*** b = new TObject**[nBs];
00953    for (int i = 0; i < nTCs; i++) {
00954       b[2*i]   = tcs[i]->fCont;
00955       b[2*i+1] = tcs[i]->fKeep->fCont;
00956    }
00957    b[nBs-1] = fKeep->fCont;
00958    QSort(fCont, nBs, b, 0, TMath::Min(nentries, upto-fLowerBound));
00959    delete [] b;
00960 
00961    fLast = -2;
00962    fSorted = kTRUE;
00963 }

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