// @(#)root/cont:$Name:  $:$Id: TObjectRef.cxx,v 1.2 2001/10/02 08:16:23 brun Exp $
// Author: Rene Brun   28/09/2001

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TObjectRef                                                           //
//                                                                      //
// Persistent Reference link to a TObject                               //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TObjectRef.h"
#include "TROOT.h"
#include "TProcessID.h"
#include "TFile.h"
#include "TObjArray.h"
#include "TSystem.h"

ClassImp(TObjectRef)

// A TObjectRef is a lightweight object pointing to any TObject.
// This object can be used instead of normal C++ pointers in case
//  - the referenced object R and the pointer P are not written to the same file
//  - P is read before R
//  - R and P are written to different Tree branches
//
// When a top level object (eg Event *event) is a tree/graph of many objects,
// the normal ROOT Streaming mechanism ensures that only one copy of each object
// in the tree/graph is written to the output buffer to avoid circular
// dependencies.
// However if the object event is split into several files or into several
// branches of one or more Trees, normal C++ pointers cannot be used because
// each I/O operation will write the referenced objects.
// When a TObjectRef is used to point to a TObject *robj. 
//For example in a class with
//     TObjectRef  fRef;
// one can do:
//   fRef = robj;  //to set the pointer
// this TObjectRef and robj can be written with two different I/O calls
// in the same or different files, in the same or different branches of a Tree.
// If the TObjectRef is read and the referenced object has not yet been read,
// the TObjectRef will return a null pointer. As soon as the referenced object
// will be read, the TObjectRef will point to it.
//
// TObjectRef also supports the complex situation where a TFile is updated
// multiple times on the same machine or a different machine.
//
// How does it work
// ----------------
// A TObjectRef is itself a TObject with an additional transient pointer fPID.
// When the statement fRef = robj is executed, the fRef::fUniqueID is set
// to the value "obj-gSystem". This uid is in general a small integer, even
// on a 64 bit system.
// After having set fRef, one can immediatly return the value of robj
// with "gSystem + uid" using fRef.GetObject() or the dereferencing operator ->.
//
// When the TObjectRef is written, the process id number pidf  (see TProcessID)
// is written as well as the uid.
// When the TObjectRef is read, its pointer fPID is set to the value
// stored in the TObjArray of TFile::fProcessIDs (fProcessIDs[pidf]).
//
// When a referenced object robj is written, TObject::Streamer writes
// in addition to the standard (fBits,fUniqueID) the pair uid,pidf.
// When this robj is read by TObject::Streamer, the pair uid,pidf is read.
// At this point, robj is entered into the TExmap of the TProcessID
// corresponding to pidf. 
//
// Once the referenced object robj is in memory, TObjectRef::GetObject will 
// store the object pointer robj-gSystem  into the fUniqueID such that
// the next access to the pointer will be fast (no need to search in
// the TExMap of the TProcessID anymore).
//
// Implicit use of TObjectRef in ROOT collections
// ----------------------------------------------
// The TSeqCollection (TList, TObjArray, etc) have been modified with
// additional member functions AddRef, AddRefAt, etc to create automatically
// a TObjectRef when doing, eg:
//    myArray->AddRef(robj);
//
// Example:
// Suppose a TObjArray *mytracks containing a list of Track objects
// Suppose a TObjArray *pions containing pointers to the pion tracks in mytracks.
//   This list is created with statements like: pions->AddRef(track);
// Suppose a TObjArray *muons containing pointers to the muon tracks in mytracks.
// The 3 arrays mytracks,pions and muons may be written separately.
//

//______________________________________________________________________________
 TObjectRef::TObjectRef(TObject *obj)
{
   // TObjectRef copy ctor.

   *this = obj;
   fPID = 0;
}

//______________________________________________________________________________
 TObjectRef::TObjectRef(const TObjectRef &ref)
{
}

//______________________________________________________________________________
void TObjectRef::operator=(TObject *obj)
{
   // TObjectRef assignment operator.

   UInt_t uid;
   if (obj) {
      obj->SetBit(kIsReferenced);
      uid = (char*)obj - (char*)gSystem;
   } else {
      uid = 0;
   }
   SetUniqueID(uid);
}

//______________________________________________________________________________
 TObject *TObjectRef::GetObject() 
{
   // Return a pointer to the referenced object.

   TObject *obj = 0;
   Long_t uid = (Long_t)GetUniqueID();
   if (uid == 0) return obj;
   if (!TestBit(1)) return (TObject*)(uid + (char*)gSystem);
   if (!fPID) return 0;
   obj = fPID->GetObjectWithID(uid);
   if (obj) {
      ResetBit(1);
      uid = (char*)obj - (char*)gSystem;
      SetUniqueID((UInt_t)uid);
   }
   return obj;
}

//______________________________________________________________________________
 void TObjectRef::ReadRef(TObject *obj, TBuffer &R__b, TFile *file)
{
// static function

   Long_t uid;
   Int_t pidf = 0;
   R__b >> uid; 
   R__b >> pidf;
   
   TProcessID *pid = TProcessID::ReadProcessID(pidf,file);
   
   if (pid) pid->PutObjectWithID(uid,obj);
}

//______________________________________________________________________________
 void TObjectRef::SaveRef(TObject *obj, TBuffer &R__b, TFile *file)
{
// static function

   Long_t uid = (char*)obj - (char*)gSystem;
   Int_t pidf = 0;
   if (file) {
      pidf = file->GetProcessCount();
   }
   R__b << uid;
   R__b << pidf;
}

//______________________________________________________________________________
 void TObjectRef::Streamer(TBuffer &R__b)
{
   // Stream an object of class TObjectRef.

   Long_t uid;
   Int_t pidf;
   if (R__b.IsReading()) {
      R__b >> pidf;
      R__b >> uid;
      SetBit(1,1);
      SetUniqueID((UInt_t)uid);
      fPID = TProcessID::ReadProcessID(pidf,gFile);
   } else {
      uid = (Long_t)GetUniqueID();
      if (gFile) pidf = gFile->GetProcessCount();
      else       pidf = 0;
      R__b << pidf;
      R__b << uid;
   }
}


ROOT page - Class index - Top of the page

This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.