Logo ROOT  
Reference Guide
Go to the documentation of this file.
1// @(#)root/cont:$Id$
2// Author: Rene Brun 28/09/2001
5 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
12/** \class TRef
13\ingroup Base
15Persistent Reference link to a TObject
16A TRef is a lightweight object pointing to any TObject.
17This object can be used instead of normal C++ pointers in case
19 - the referenced object R and the pointer P are not written to the same file
20 - P is read before R
21 - R and P are written to different Tree branches
23When a top level object (eg Event *event) is a tree/graph of many objects,
24the normal ROOT Streaming mechanism ensures that only one copy of each object
25in the tree/graph is written to the output buffer to avoid circular
28However if the object event is split into several files or into several
29branches of one or more Trees, normal C++ pointers cannot be used because
30each I/O operation will write the referenced objects.
32When a TRef is used to point to a TObject *robj, for example in a class with
33~~~ {.cpp}
34 TRef fRef;
36one can do:
37~~~ {.cpp}
38 fRef = robj; //to set the pointer
40This TRef and robj can be written with two different I/O calls
41in the same or different files, in the same or different branches of a Tree.
43If the TRef is read and the referenced object has not yet been read,
44the TRef will return a null pointer. As soon as the referenced object
45will be read, the TRef will point to it. If the referenced object is
46contained in a TTree it can be auto-loaded using the TBranchRef mechanism,
47which is set up by simply calling TTree::BranchRef().
49TRef also supports the complex situation where a TFile is updated
50multiple times on the same machine or a different machine.
52## How does it work
54A TRef is itself a TObject with an additional transient pointer fPID.
55When the statement fRef = robj is executed, the following actions happen:
57 - The pointer fPID is set to the current TProcessID.
58 - The current ObjectNumber (see below) is incremented by one.
59 - robj::fUniqueID is set to ObjectNumber.
60 - In the fPID object, the element fObjects[ObjectNumber] is set to robj
61 - ref::fUniqueID is also set to ObjectNumber.
63After having set fRef, one can immediately return the value of robj
64using fRef.GetObject(). This function returns directly fObjects[fUniqueID]
65from the fPID object.
67When the TRef is written, the process id number pidf of fPID is written
68in addition to the TObject part of TRef (fBits,fUniqueID).
70When the TRef is read, its pointer fPID is set to the value
71stored in the TObjArray of TFile::fProcessIDs (fProcessIDs[pidf]).
72The pidf is stored as a UShort_t limiting a file to 65535 distinct
73ProcessID objects.
75The pidf is stored in the bits 24->31 of the fUniqueID of the TRef.
76This implies that the number of TRefs in a single ProcessID should not
77exceed 2**24 = 16777216. For pidf greater than 254, the value 0xff is
78stored in those bits and we use the table TProcessID::fgObjPIDs which
79links the referenced object's address to its ProcessID.
81See section "ObjectNumber" below for a recipe to minimize the object count.
82If the object-number exceeds this limit, it could be the sign that:
84 - The object count is never reset (see below)
85 - TRef is misused.
87When a referenced object robj is written, TObject::Streamer writes
88in addition to the standard (fBits,fUniqueID) the pidf.
89When this robj is read by TObject::Streamer, the pidf is read.
90At this point, robj is entered into the table of objects of the TProcessID
91corresponding to pidf.
93### WARNING1:
94If MyClass is the class of the referenced object, The TObject
95part of MyClass must be Streamed. One should not
96call MyClass::Class()->IgnoreTObjectStreamer()
98### WARNING2:
99A TRef cannot point to another TRef.
101## ObjectNumber
103When an object is referenced (see TRef assignment operator or TRefArray::Add)
104a unique identifier is computed and stored in both the fUniqueID of the
105referenced and referencing object. This uniqueID is computed by incrementing
106by one the static global in TProcessID::fgNumber. fUniqueID is some sort of
107serial object number in the current session. One can retrieve at any time
108the current value of fgNumber by calling the static function TProcessID::GetObjectCount
109or set this number via TProcessID::SetObjectCount.
111To avoid a growing table of fObjects in TProcessID, in case, for example,
112one processes many events in a loop, it might be necessary to reset the
113ObjectNumber at the end of processing of one event. See an example
114in $ROOTSYS/test/Event.cxx (look at function Build).
116The value of ObjectNumber (say saveNumber=TProcessID::GetObjectCount()) may be
117saved at the beginning of one event and reset to this original value
118at the end of the event via TProcessID::SetObjectCount(saveNumber). These
119actions may be stacked.
121## Action on Demand
123The normal behaviour of a TRef has been described above. In addition,
124TRef supports also "Actions on Demand". It may happen that the object
125referenced is not yet in memory, on a separate file or not yet computed.
126In this case TRef is able to automatically execute an action:
128 - call to a compiled function (static function of member function)
129 - call to an interpreted function
130 - execution of a C++ script
132How to select this option?
133In the definition of the TRef data member in the original class, do:
134~~~ {.cpp}
135 TRef fRef; //EXEC:execName. points to something
137When the special keyword "EXEC:" is found in the comment field of the member,
138the next string is assumed to be the name of a TExec object.
139When a file is connected, the dictionary of the classes on the file
140is read in memory (see TFile::ReadStreamerInfo). When the TStreamerElement
141object is read, a TExec object is automatically created with the name
142specified after the keyword "EXEC:" in case a TExec with a same name does
143not already exist.
145The action to be executed via this TExec can be specified with:
147 - a call to the TExec constructor, if the constructor is called before
148 opening the file.
149 - a call to TExec::SetAction at any time.
150 One can compute a pointer to an existing TExec with a name with:
151~~~ {.cpp}
152 TExec *myExec = gROOT->GetExec(execName);
153 myExec->SetAction(actionCommand);
155 where actionCommand is a string containing a C++ instruction. Examples:
156~~~ {.cpp}
157 myExec->SetAction("LoadHits()");
158 myExec->SetAction(".x script.C");
161When a TRef is dereferenced via TRef::GetObject, its TExec will be
162automatically executed. In the function/script being executed, one or more
163of the following actions can be executed:
165 - load a file containing the referenced object. This function typically
166 looks in the file catalog (GRID).
167 - compute a pointer to the referenced object and communicate this pointer
168 back to the calling function TRef::GetObject via:
169~~~ {.cpp}
170 TRef::SetStaticObject(object).
172 When the TExec is called, it has access to the dereferencing TRef
173 by calling GetStaticObject() (TRef::GetObject() sets fgObject to "this"
174 before the call to TExec). This can be useful for accessing the TRef's
175 fUniqueID.
177As soon as an object is returned to GetObject, the fUniqueID of the TRef is set
178to the fUniqueID of the referenced object. At the next call to GetObject,
179the pointer stored in fPid:fObjects[fUniqueID] will be returned directly.
181An example of action on demand is shown in $ROOTSYS/test/Event.h with
182the member:
183~~~ {.cpp}
184 TRef fWebHistogram; //EXEC:GetWebHistogram
186When calling fWebHistogram.GetObject(), the function GetObject
187will automatically invoke a script GetWebHistogram.C via the interpreter.
189An example of a GetWebHistogram.C script is shown below
190~~~ {.cpp}
191 void GetWebHistogram() {
192 TFile *f= TFile::Open("http://root.cern.ch/files/pippa.root");
193 f->cd("DM/CJ");
194 TH1 *h6 = (TH1*)gDirectory->Get("h6");
195 h6->SetDirectory(0);
196 delete f;
197 TRef::SetStaticObject(h6);
198 }
200In the above example, a call to fWebHistogram.GetObject() executes the
201script with the function GetWebHistogram. This script connects a file
202with histograms: pippa.root on the ROOT Web site and returns the object h6
203to TRef::GetObject.
205Note that if the definition of the TRef fWebHistogram had been:
206~~~ {.cpp}
207 TRef fWebHistogram; //EXEC:GetWebHistogram()
209then, the compiled or interpreted function GetWebHistogram() would have
210been called instead of the C++ script GetWebHistogram.C
212## Special case of a TRef pointing to an object with a TUUID
214If the referenced object has a TUUID, its bit kHasUUID has been set.
215This case is detected by the TRef assignment operator.
216(For example, TFile and TDirectory have a TUUID)
217The TRef fPID points directly to the single object TProcessUUID (deriving
218from TProcessID) and managing the list of TUUIDs for a process.
219The TRef kHasUUID bit is set and its fUniqueID is set to the fUniqueID
220of the referenced object.
222When the TRef is streamed to a buffer, the corresponding TUUID is also
223streamed with the TRef. When a TRef is read from a buffer, the corresponding
224TUUID is also read and entered into the global list of TUUIDs (if not
225already there). The TRef fUniqueID is set to the UUIDNumber.
226see TProcessUUID for more details.
228## Array of TRef
230The special class TRefArray should be used to store multiple references.
231A TRefArray has one single pointer fPID for all objects in the array.
232It has a dynamic compact table of fUniqueIDs. Use a TRefArray rather
233then a collection of TRefs if all TRefs stem from the same process.
237Suppose a TObjArray *mytracks containing a list of Track objects
238Suppose a TRefArray *pions containing pointers to the pion tracks in mytracks.
239This list is created with statements like: pions->Add(track);
240Suppose a TRefArray *muons containing pointers to the muon tracks in mytracks.
241The 3 arrays mytracks,pions and muons may be written separately.
244#include "TRef.h"
245#include "TROOT.h"
246#include "TBuffer.h"
247#include "TClass.h"
248#include "TProcessUUID.h"
249#include "TRefTable.h"
250#include "TObjArray.h"
251#include "TExec.h"
252#include "TSystem.h"
253#include "TObjString.h"
261/// Create a ref to obj.
265 *this = obj;
269/// TRef copy ctor.
271TRef::TRef(const TRef &ref) : TObject(ref)
273 *this = ref;
277/// Assign object to reference.
281 UInt_t uid = 0;
282 fPID = 0;
283 if (obj) {
284 if (obj->IsA()->CanIgnoreTObjectStreamer()) {
285 Error("operator= ","Class: %s IgnoreTObjectStreamer. Cannot reference object",obj->ClassName());
286 return;
287 }
288 if (obj->TestBit(kHasUUID)) {
289 fPID = gROOT->GetUUIDs();
290 obj->SetBit(kIsReferenced);
292 uid = obj->GetUniqueID();
293 } else {
294 if (!obj->TestBit(kIsReferenced)) {
296 }
297 uid = obj->GetUniqueID();
300 }
301 }
302 SetUniqueID(uid);
306/// TRef assignment operator.
310 if (this != &ref) {
312 fPID = ref.fPID;
314 }
315 return *this;
319/// Return kTRUE if r1 and r2 point to the same object.
321Bool_t operator==(const TRef &r1, const TRef &r2)
323 if (r1.GetPID() == r2.GetPID() && r1.GetUniqueID() == r2.GetUniqueID()) return kTRUE;
324 else return kFALSE;
328/// Return kTRUE if r1 and r2 do not point to the same object.
330Bool_t operator!=(const TRef &r1, const TRef &r2)
332 if (r1.GetPID() == r2.GetPID() && r1.GetUniqueID() == r2.GetUniqueID()) return kFALSE;
333 else return kTRUE;
337/// If Exec with name does not exist in the list of Execs, it is created.
338/// returns the index of the Exec in the list.
343 if (!fgExecs) GetListOfExecs();
345 if (!fgExecs) fgExecs = new TObjArray(10);
348 TExec *exec = (TExec*)fgExecs->FindObject(name);
349 if (!exec) {
350 // we register this Exec to the list of Execs.
351 exec = new TExec(name,"");
352 fgExecs->Add(exec);
353 }
354 return fgExecs->IndexOf(exec);
358/// Return a pointer to the static TObjArray holding the list of Execs.
363 static TObjArray listOfExecs(10);
364 if (!fgExecs) {
365 listOfExecs.SetOwner(kTRUE);
366 fgExecs = &listOfExecs;
367 }
369 if (!fgExecs) fgExecs = new TObjArray(10);
371 return fgExecs;
376/// Return a pointer to the referenced object.
380 //TObject *obj = 0;
381 if (!fPID) return 0;
382 if (!TProcessID::IsValid(fPID)) return 0;
383 UInt_t uid = GetUniqueID();
385 //the reference may be in the TRefTable
387 if (table) {
389 table->SetUID(uid, fPID);
390 table->Notify();
391 }
393 //Try to find the object from the table of the corresponding PID
394 TObject *obj = fPID->GetObjectWithID(uid);
396 //if object not found, then exec action if an action has been defined
397 if (!obj) {
398 //execid in the first 8 bits
399 Int_t execid = TestBits(0xff0000);
400 if (execid > 0) {
401 execid = execid>>16;
403 TExec *exec = (TExec*)fgExecs->At(execid-1);
404 if (exec) {
405 //we expect the object to be returned via TRef::SetStaticObject
406 fgObject = const_cast<TRef*>(this);
407 exec->Exec();
408 if ((const TRef*)fgObject != this)
409 obj = fgObject;
410 else obj=0;
411 if (obj){
412 uid = TProcessID::AssignID(obj);
413 ((TRef*)this)->SetUniqueID(uid);
414 fPID->PutObjectWithID(obj,uid);
415 } else {
416 //well may be the Exec has loaded the object
417 obj = fPID->GetObjectWithID(uid);
418 }
419 }
420 }
421 }
423 return obj;
427/// Store the exec number (in the ROOT list of Execs)
428/// into the fBits of this TRef.
430void TRef::SetAction(const char *name)
433 if (!exec) {
434 Error("SetAction","Unknown TExec: %s",name);
435 return;
436 }
437 Int_t execid = 1 + fgExecs->IndexOf(exec);
438 SetBit(execid << 16);
442/// Find the action to be executed in the dictionary of the parent class
443/// and store the corresponding exec number into fBits.
444/// This function searches a data member in the class of parent with an
445/// offset corresponding to this.
446/// If a comment "TEXEC:" is found in the comment field of the data member,
447/// the function stores the exec identifier of the exec statement
448/// following this keyword.
452 if (!parent) return;
453 if (gDirectory) gDirectory->SetTRefAction(this,parent);
456 ///////////////////////////////////////////////////////////////////////////////
457 /// Returns the static object.
460 return fgObject;
464/// static Obsolete function kept for back compatibility.
465/// In the near future will print a Warning, then will be deleted.
469 SetStaticObject(obj);
473/// Static function to set the object found on the Action on Demand function.
474/// This function may be called by the user in the function called
475/// when a "EXEC:" keyword is specified in the data member field of the TRef.
476/// The function can get access to the dereferencing TRef (i.e. this)using
477/// the static function GetStaticObject().
481 fgObject = obj;
485/// Stream an object of class TRef.
487void TRef::Streamer(TBuffer &R__b)
489 UShort_t pidf;
490 if (R__b.IsReading()) {
491 TObject::Streamer(R__b);
492 if (TestBit(kHasUUID)) {
493 TString s;
494 s.Streamer(R__b);
495 TProcessUUID *pid = gROOT->GetUUIDs();
496 UInt_t number = pid->AddUUID(s.Data());
497 fPID = pid;
498 SetUniqueID(number);
499 if (gDebug > 1) {
500 printf("Reading TRef (HasUUID) uid=%d, obj=%lx\n",GetUniqueID(),(Long_t)GetObject());
501 }
502 } else {
503 R__b >> pidf;
504 pidf += R__b.GetPidOffset();
505 fPID = R__b.ReadProcessID(pidf);
506 //The execid has been saved in the unique id of the TStreamerElement
507 //being read by TStreamerElement::Streamer
508 //The current element (fgElement) is set as a static global
509 //by TStreamerInfo::ReadBuffer (Clones) when reading this TRef
510 Int_t execid = R__b.GetTRefExecId();
511 if (execid) SetBit(execid<<16);
512 if (gDebug > 1) {
513 printf("Reading TRef, pidf=%d, fPID=%lx, uid=%d, obj=%lx\n",pidf,(Long_t)fPID,GetUniqueID(),(Long_t)GetObject());
514 }
515 }
516 } else {
517 TObject::Streamer(R__b);
519 if (TestBit(kHasUUID)) {
520 TObjString *objs = gROOT->GetUUIDs()->FindUUID(GetUniqueID());
521 objs->String().Streamer(R__b);
522 if (gDebug > 1) {
523 printf("Writing TRef (HasUUID) uid=%d, obj=%lx\n",GetUniqueID(),(Long_t)GetObject());
524 }
525 } else {
526 pidf = R__b.WriteProcessID(fPID);
527 R__b << pidf;
528 if (gDebug > 1) {
529 printf("Writing TRef, pidf=%d, fPID=%lx, uid=%d, obj=%lx\n",pidf,(Long_t)fPID,GetUniqueID(),(Long_t)GetObject());
530 }
531 }
532 }
unsigned short UShort_t
Definition: RtypesCore.h:38
int Int_t
Definition: RtypesCore.h:43
unsigned int UInt_t
Definition: RtypesCore.h:44
const Bool_t kFALSE
Definition: RtypesCore.h:90
long Long_t
Definition: RtypesCore.h:52
R__EXTERN Int_t gDebug
Definition: RtypesCore.h:117
const Bool_t kTRUE
Definition: RtypesCore.h:89
#define ClassImp(name)
Definition: Rtypes.h:361
#define gDirectory
Definition: TDirectory.h:229
char name[80]
Definition: TGX11.cxx:109
#define gROOT
Definition: TROOT.h:406
Bool_t operator==(const TRef &r1, const TRef &r2)
Return kTRUE if r1 and r2 point to the same object.
Definition: TRef.cxx:321
Bool_t operator!=(const TRef &r1, const TRef &r2)
Return kTRUE if r1 and r2 do not point to the same object.
Definition: TRef.cxx:330
#define R__WRITE_LOCKGUARD(mutex)
Buffer base class used for serializing objects.
Definition: TBuffer.h:42
virtual UInt_t GetTRefExecId()=0
virtual TProcessID * ReadProcessID(UShort_t pidf)=0
Return the current Process-ID.
Definition: TBuffer.cxx:344
virtual UShort_t WriteProcessID(TProcessID *pid)=0
Always return 0 (current processID).
Definition: TBuffer.cxx:353
virtual UShort_t GetPidOffset() const =0
Bool_t IsReading() const
Definition: TBuffer.h:85
virtual void SetOwner(Bool_t enable=kTRUE)
Set whether this collection is the owner (enable==true) of its content.
TExec is a utility class that can be used to execute a C++ command when some event happens in a pad.
Definition: TExec.h:28
virtual void Exec(const char *command="")
Execute the command referenced by this object.
Definition: TExec.cxx:143
An array of TObjects.
Definition: TObjArray.h:37
Int_t IndexOf(const TObject *obj) const
Definition: TObjArray.cxx:605
void Add(TObject *obj)
Definition: TObjArray.h:74
virtual TObject * FindObject(const char *name) const
Find an object in this collection using its name.
Definition: TObjArray.cxx:415
TObject * At(Int_t idx) const
Definition: TObjArray.h:166
Collectable string class.
Definition: TObjString.h:28
TString & String()
Definition: TObjString.h:48
Mother of all ROOT objects.
Definition: TObject.h:37
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition: TObject.h:187
virtual UInt_t GetUniqueID() const
Return the unique object id.
Definition: TObject.cxx:375
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition: TObject.cxx:128
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition: TObject.cxx:694
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:891
virtual void SetUniqueID(UInt_t uid)
Set the unique object id.
Definition: TObject.cxx:705
Int_t TestBits(UInt_t f) const
Definition: TObject.h:188
void ResetBit(UInt_t f)
Definition: TObject.h:186
@ kHasUUID
if object has a TUUID (its fUniqueID=UUIDNumber)
Definition: TObject.h:62
@ kIsReferenced
if object is referenced by a TRef or TRefArray
Definition: TObject.h:61
static Bool_t IsValid(TProcessID *pid)
static function. return kTRUE if pid is a valid TProcessID
Definition: TProcessID.cxx:358
static UInt_t AssignID(TObject *obj)
static function returning the ID assigned to obj If the object is not yet referenced,...
Definition: TProcessID.cxx:153
void PutObjectWithID(TObject *obj, UInt_t uid=0)
stores the object at the uid th slot in the table of objects The object uniqued is set as well as its...
Definition: TProcessID.cxx:381
static TProcessID * GetProcessWithUID(const TObject *obj)
static function returning a pointer to TProcessID with its pid encoded in the highest byte of obj->Ge...
Definition: TProcessID.cxx:295
TObject * GetObjectWithID(UInt_t uid)
returns the TObject with unique identifier uid in the table of objects
Definition: TProcessID.cxx:330
This class is a specialized TProcessID managing the list of UUIDs.
Definition: TProcessUUID.h:32
UInt_t AddUUID(TUUID &uuid, TObject *obj)
Add uuid to the table of UUIDs The TObject *obj has its uniqueID set to the UUID number return entry ...
A TRefTable maintains the association between a referenced object and the parent object supporting th...
Definition: TRefTable.h:35
virtual Bool_t Notify()
This function is called by TRef::Streamer or TStreamerInfo::ReadBuffer when reading a reference.
Definition: TRefTable.cxx:299
static TRefTable * GetRefTable()
Static function returning the current TRefTable.
Definition: TRefTable.cxx:287
virtual void SetUID(UInt_t uid, TProcessID *context=0)
Definition: TRefTable.h:87
Persistent Reference link to a TObject A TRef is a lightweight object pointing to any TObject.
Definition: TRef.h:32
static void SetObject(TObject *obj)
static Obsolete function kept for back compatibility.
Definition: TRef.cxx:467
static void SetStaticObject(TObject *obj)
Static function to set the object found on the Action on Demand function.
Definition: TRef.cxx:479
void operator=(TObject *obj)
Assign object to reference.
Definition: TRef.cxx:279
static TObject * fgObject
Definition: TRef.h:38
Definition: TRef.h:42
TProcessID * GetPID() const
Definition: TRef.h:50
static TObject * GetStaticObject()
Returns the static object.
Definition: TRef.cxx:459
virtual void SetAction(const char *name)
Store the exec number (in the ROOT list of Execs) into the fBits of this TRef.
Definition: TRef.cxx:430
TObject * GetObject() const
Return a pointer to the referenced object.
Definition: TRef.cxx:378
TProcessID * fPID
Definition: TRef.h:35
static TObjArray * GetListOfExecs()
Return a pointer to the static TObjArray holding the list of Execs.
Definition: TRef.cxx:360
static Int_t AddExec(const char *name)
If Exec with name does not exist in the list of Execs, it is created.
Definition: TRef.cxx:340
static TObjArray * fgExecs
Pointer to ProcessID when TRef was written.
Definition: TRef.h:37
Basic string class.
Definition: TString.h:131
R__EXTERN TVirtualRWMutex * gCoreMutex
static constexpr double s