Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TRef.cxx
Go to the documentation of this file.
1// @(#)root/cont:$Id$
2// Author: Rene Brun 28/09/2001
3
4/*************************************************************************
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 *************************************************************************/
11
12/** \class TRef
13\ingroup Base
14
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
18
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
22
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
26dependencies.
27
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.
31
32When a TRef is used to point to a TObject *robj, for example in a class with
33~~~ {.cpp}
34 TRef fRef;
35~~~
36one can do:
37~~~ {.cpp}
38 fRef = robj; //to set the pointer
39~~~
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.
42
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().
48
49TRef also supports the complex situation where a TFile is updated
50multiple times on the same machine or a different machine.
51
52## How does it work
53
54A TRef is itself a TObject with an additional transient pointer fPID.
55When the statement fRef = robj is executed, the following actions happen:
56
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.
62
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.
66
67When the TRef is written, the process id number pidf of fPID is written
68in addition to the TObject part of TRef (fBits,fUniqueID).
69
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.
74
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.
80
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:
83
84 - The object count is never reset (see below)
85 - TRef is misused.
86
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.
92
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()
97
98### WARNING2:
99A TRef cannot point to another TRef.
100
101## ObjectNumber
102
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.
110
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).
115
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.
120
121## Action on Demand
122
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:
127
128 - call to a compiled function (static function of member function)
129 - call to an interpreted function
130 - execution of a C++ script
131
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
136~~~
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.
144
145The action to be executed via this TExec can be specified with:
146
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);
154~~~
155 where actionCommand is a string containing a C++ instruction. Examples:
156~~~ {.cpp}
157 myExec->SetAction("LoadHits()");
158 myExec->SetAction(".x script.C");
159~~~
160
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:
164
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).
171~~~
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.
176
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.
180
181An example of action on demand is shown in $ROOTSYS/test/Event.h with
182the member:
183~~~ {.cpp}
184 TRef fWebHistogram; //EXEC:GetWebHistogram
185~~~
186When calling fWebHistogram.GetObject(), the function GetObject
187will automatically invoke a script GetWebHistogram.C via the interpreter.
188
189An example of a GetWebHistogram.C script is shown below
190~~~ {.cpp}
191 void GetWebHistogram() {
192 TFile *f= TFile::Open("http://root.cern/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 }
199~~~
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.
204
205Note that if the definition of the TRef fWebHistogram had been:
206~~~ {.cpp}
207 TRef fWebHistogram; //EXEC:GetWebHistogram()
208~~~
209then, the compiled or interpreted function GetWebHistogram() would have
210been called instead of the C++ script GetWebHistogram.C
211
212## Special case of a TRef pointing to an object with a TUUID
213
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.
221
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.
227
228## Array of TRef
229
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.
234
235Example:
236
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.
242*/
243
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 "TObjString.h"
253
254TObjArray *TRef::fgExecs = nullptr;
255TObject *TRef::fgObject = nullptr;
256
257
258////////////////////////////////////////////////////////////////////////////////
259/// Create a ref to obj.
260
262{
263 *this = obj;
264}
265
266////////////////////////////////////////////////////////////////////////////////
267/// TRef copy ctor.
268
270{
271 *this = ref;
272}
273
274////////////////////////////////////////////////////////////////////////////////
275/// Assign object to reference.
276
278{
279 UInt_t uid = 0;
280 fPID = nullptr;
281 if (obj) {
282 if (obj->IsA()->CanIgnoreTObjectStreamer()) {
283 Error("operator= ","Class: %s IgnoreTObjectStreamer. Cannot reference object",obj->ClassName());
284 return;
285 }
286 if (obj->TestBit(kHasUUID)) {
287 fPID = gROOT->GetUUIDs();
288 obj->SetBit(kIsReferenced);
290 uid = obj->GetUniqueID();
291 } else {
292 if (!obj->TestBit(kIsReferenced)) {
294 }
295 uid = obj->GetUniqueID();
298 }
299 }
300 SetUniqueID(uid);
301}
302
303////////////////////////////////////////////////////////////////////////////////
304/// TRef assignment operator.
305
307{
308 if (this != &ref) {
309 SetUniqueID(ref.GetUniqueID());
310 fPID = ref.fPID;
311 SetBit(kHasUUID,ref.TestBit(kHasUUID));
312 }
313 return *this;
314}
315
316////////////////////////////////////////////////////////////////////////////////
317/// Return kTRUE if r1 and r2 point to the same object.
318
320{
321 if (r1.GetPID() == r2.GetPID() && r1.GetUniqueID() == r2.GetUniqueID()) return kTRUE;
322 else return kFALSE;
323}
324
325////////////////////////////////////////////////////////////////////////////////
326/// Return kTRUE if r1 and r2 do not point to the same object.
327
329{
330 if (r1.GetPID() == r2.GetPID() && r1.GetUniqueID() == r2.GetUniqueID()) return kFALSE;
331 else return kTRUE;
332}
333
334////////////////////////////////////////////////////////////////////////////////
335/// If Exec with name does not exist in the list of Execs, it is created.
336/// returns the index of the Exec in the list.
337
339{
340#ifdef R__COMPLETE_MEM_TERMINATION
341 if (!fgExecs) GetListOfExecs();
342#else
343 if (!fgExecs) fgExecs = new TObjArray(10);
344#endif
345
346 TExec *exec = (TExec*)fgExecs->FindObject(name);
347 if (!exec) {
348 // we register this Exec to the list of Execs.
349 exec = new TExec(name,"");
350 fgExecs->Add(exec);
351 }
352 return fgExecs->IndexOf(exec);
353}
354
355////////////////////////////////////////////////////////////////////////////////
356/// Return a pointer to the static TObjArray holding the list of Execs.
357
359{
360#ifdef R__COMPLETE_MEM_TERMINATION
361 static TObjArray listOfExecs(10);
362 if (!fgExecs) {
363 listOfExecs.SetOwner(kTRUE);
365 }
366#else
367 if (!fgExecs) fgExecs = new TObjArray(10);
368#endif
369 return fgExecs;
370
371}
372
373////////////////////////////////////////////////////////////////////////////////
374/// Return a pointer to the referenced object.
375
377{
378 //TObject *obj = 0;
379 if (!fPID) return nullptr;
380 if (!TProcessID::IsValid(fPID)) return nullptr;
381 UInt_t uid = GetUniqueID();
382
383 //the reference may be in the TRefTable
385 if (table) {
387 table->SetUID(uid, fPID);
388 table->Notify();
389 }
390
391 //Try to find the object from the table of the corresponding PID
392 TObject *obj = fPID->GetObjectWithID(uid);
393
394 //if object not found, then exec action if an action has been defined
395 if (!obj) {
396 //execid in the first 8 bits
397 Int_t execid = TestBits(0xff0000);
398 if (execid > 0) {
399 execid = execid>>16;
401 TExec *exec = (TExec*)fgExecs->At(execid-1);
402 if (exec) {
403 //we expect the object to be returned via TRef::SetStaticObject
404 fgObject = const_cast<TRef*>(this);
405 exec->Exec();
406 if ((const TRef*)fgObject != this)
407 obj = fgObject;
408 else obj=nullptr;
409 if (obj){
410 uid = TProcessID::AssignID(obj);
411 ((TRef*)this)->SetUniqueID(uid);
412 fPID->PutObjectWithID(obj,uid);
413 } else {
414 //well may be the Exec has loaded the object
415 obj = fPID->GetObjectWithID(uid);
416 }
417 }
418 }
419 }
420
421 return obj;
422}
423
424////////////////////////////////////////////////////////////////////////////////
425/// Store the exec number (in the ROOT list of Execs)
426/// into the fBits of this TRef.
427
428void TRef::SetAction(const char *name)
429{
430 TExec *exec = (TExec*)GetListOfExecs()->FindObject(name);
431 if (!exec) {
432 Error("SetAction","Unknown TExec: %s",name);
433 return;
434 }
435 Int_t execid = 1 + fgExecs->IndexOf(exec);
436 SetBit(execid << 16);
437}
438
439////////////////////////////////////////////////////////////////////////////////
440/// Find the action to be executed in the dictionary of the parent class
441/// and store the corresponding exec number into fBits.
442/// This function searches a data member in the class of parent with an
443/// offset corresponding to this.
444/// If a comment "TEXEC:" is found in the comment field of the data member,
445/// the function stores the exec identifier of the exec statement
446/// following this keyword.
447
449{
450 if (!parent) return;
451 if (gDirectory) gDirectory->SetTRefAction(this,parent);
452}
453
454 ///////////////////////////////////////////////////////////////////////////////
455 /// Returns the static object.
456
460
461////////////////////////////////////////////////////////////////////////////////
462/// static Obsolete function kept for back compatibility.
463/// In the near future will print a Warning, then will be deleted.
464
466{
467 SetStaticObject(obj);
468}
469
470////////////////////////////////////////////////////////////////////////////////
471/// Static function to set the object found on the Action on Demand function.
472/// This function may be called by the user in the function called
473/// when a "EXEC:" keyword is specified in the data member field of the TRef.
474/// The function can get access to the dereferencing TRef (i.e. this)using
475/// the static function GetStaticObject().
476
478{
479 fgObject = obj;
480}
481
482////////////////////////////////////////////////////////////////////////////////
483/// Stream an object of class TRef.
484
486{
488 if (R__b.IsReading()) {
490 if (TestBit(kHasUUID)) {
491 TString s;
492 s.Streamer(R__b);
493 TProcessUUID *pid = gROOT->GetUUIDs();
494 UInt_t number = pid->AddUUID(s.Data());
495 fPID = pid;
496 SetUniqueID(number);
497 if (gDebug > 1) {
498 printf("Reading TRef (HasUUID) uid=%d, obj=%zx\n",GetUniqueID(),(size_t)GetObject());
499 }
500 } else {
501 R__b >> pidf;
502 pidf += R__b.GetPidOffset();
503 fPID = R__b.ReadProcessID(pidf);
504 //The execid has been saved in the unique id of the TStreamerElement
505 //being read by TStreamerElement::Streamer
506 //The current element (fgElement) is set as a static global
507 //by TStreamerInfo::ReadBuffer (Clones) when reading this TRef
508 Int_t execid = R__b.GetTRefExecId();
509 if (execid) SetBit(execid<<16);
510 if (gDebug > 1) {
511 printf("Reading TRef, pidf=%d, fPID=%zx, uid=%d, obj=%zx\n",pidf,(size_t)fPID,GetUniqueID(),(size_t)GetObject());
512 }
513 }
514 } else {
516
517 if (TestBit(kHasUUID)) {
518 TObjString *objs = gROOT->GetUUIDs()->FindUUID(GetUniqueID());
519 objs->String().Streamer(R__b);
520 if (gDebug > 1) {
521 printf("Writing TRef (HasUUID) uid=%d, obj=%zx\n",GetUniqueID(),(size_t)GetObject());
522 }
523 } else {
524 pidf = R__b.WriteProcessID(fPID);
525 R__b << pidf;
526 if (gDebug > 1) {
527 printf("Writing TRef, pidf=%d, fPID=%zx, uid=%d, obj=%zx\n",pidf,(size_t)fPID,GetUniqueID(),(size_t)GetObject());
528 }
529 }
530 }
531}
constexpr Bool_t kFALSE
Definition RtypesCore.h:108
constexpr Bool_t kTRUE
Definition RtypesCore.h:107
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define gDirectory
Definition TDirectory.h:385
char name[80]
Definition TGX11.cxx:110
Int_t gDebug
Global variable setting the debug level. Set to 0 to disable, increase it in steps of 1 to increase t...
Definition TROOT.cxx:627
#define gROOT
Definition TROOT.h:411
Bool_t operator==(const TRef &r1, const TRef &r2)
Return kTRUE if r1 and r2 point to the same object.
Definition TRef.cxx:319
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:328
#define R__WRITE_LOCKGUARD(mutex)
Buffer base class used for serializing objects.
Definition TBuffer.h:43
TExec is a utility class that can be used to execute a C++ command when some event happens in a pad.
Definition TExec.h:26
virtual void Exec(const char *command="")
Execute the command referenced by this object.
Definition TExec.cxx:142
An array of TObjects.
Definition TObjArray.h:31
Collectable string class.
Definition TObjString.h:28
Mother of all ROOT objects.
Definition TObject.h:41
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition TObject.h:202
virtual UInt_t GetUniqueID() const
Return the unique object id.
Definition TObject.cxx:475
virtual void Streamer(TBuffer &)
Stream an object of class TObject.
Definition TObject.cxx:972
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition TObject.cxx:226
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition TObject.cxx:864
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1071
virtual void SetUniqueID(UInt_t uid)
Set the unique object id.
Definition TObject.cxx:875
Int_t TestBits(UInt_t f) const
Definition TObject.h:203
virtual TClass * IsA() const
Definition TObject.h:246
void ResetBit(UInt_t f)
Definition TObject.h:201
@ kHasUUID
if object has a TUUID (its fUniqueID=UUIDNumber)
Definition TObject.h:72
@ kIsReferenced
if object is referenced by a TRef or TRefArray
Definition TObject.h:71
static Bool_t IsValid(TProcessID *pid)
static function. return kTRUE if pid is a valid TProcessID
static UInt_t AssignID(TObject *obj)
static function returning the ID assigned to obj If the object is not yet referenced,...
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...
static TProcessID * GetProcessWithUID(const TObject *obj)
static function returning a pointer to TProcessID with its pid encoded in the highest byte of obj->Ge...
TObject * GetObjectWithID(UInt_t uid)
returns the TObject with unique identifier uid in the table of objects
This class is a specialized TProcessID managing the list of UUIDs.
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 ...
TList * GetUUIDs() const
A TRefTable maintains the association between a referenced object and the parent object supporting th...
Definition TRefTable.h:35
virtual void SetUID(UInt_t uid, TProcessID *context=nullptr)
Definition TRefTable.h:91
static TRefTable * GetRefTable()
Static function returning the current TRefTable.
Bool_t Notify() override
This function is called by TRef::Streamer or TStreamerInfo::ReadBuffer when reading a reference.
Persistent Reference link to a TObject A TRef is a lightweight object pointing to any TObject.
Definition TRef.h:32
void Streamer(TBuffer &) override
Stream an object of class TRef.
Definition TRef.cxx:485
static void SetObject(TObject *obj)
static Obsolete function kept for back compatibility.
Definition TRef.cxx:465
static void SetStaticObject(TObject *obj)
Static function to set the object found on the Action on Demand function.
Definition TRef.cxx:477
void operator=(TObject *obj)
Assign object to reference.
Definition TRef.cxx:277
static TObject * fgObject
Definition TRef.h:38
TRef()
Definition TRef.h:42
static TObject * GetStaticObject()
Returns the static object.
Definition TRef.cxx:457
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:428
TObject * GetObject() const
Return a pointer to the referenced object.
Definition TRef.cxx:376
TProcessID * fPID
Definition TRef.h:35
static TObjArray * GetListOfExecs()
Return a pointer to the static TObjArray holding the list of Execs.
Definition TRef.cxx:358
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:338
static TObjArray * fgExecs
Pointer to ProcessID when TRef was written.
Definition TRef.h:37
Basic string class.
Definition TString.h:138
const char * Data() const
Definition TString.h:384
virtual void Streamer(TBuffer &)
Stream a string object.
Definition TString.cxx:1418
R__EXTERN TVirtualRWMutex * gCoreMutex