forked from root-project/root
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTObject.h
More file actions
429 lines (368 loc) · 17.8 KB
/
TObject.h
File metadata and controls
429 lines (368 loc) · 17.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
// @(#)root/base:$Id$
// Author: Rene Brun 26/12/94
/*************************************************************************
* 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. *
*************************************************************************/
#ifndef ROOT_TObject
#define ROOT_TObject
// #include "RConfigure.h" // included via Rtypes.h
#include "Rtypes.h"
#include "TStorage.h"
#include "TVersionCheck.h"
#include <cstdarg>
#include <string>
#include <iosfwd>
#ifdef WIN32
#undef RemoveDirectory
#endif
class TList;
class TBrowser;
class TBuffer;
class TObjArray;
class TMethod;
class TTimer;
namespace ROOT {
namespace Internal {
bool DeleteChangesMemoryImpl();
}}
class TObject {
private:
UInt_t fUniqueID; ///< object unique identifier
UInt_t fBits; ///< bit field status word
static Longptr_t fgDtorOnly; ///< object for which to call dtor only (i.e. no delete)
static Bool_t fgObjectStat; ///< if true keep track of objects in TObjectTable
static void AddToTObjectTable(TObject *);
protected:
void MakeZombie() { fBits |= kZombie; }
virtual void DoError(int level, const char *location, const char *fmt, va_list va) const;
static void SavePrimitiveConstructor(std::ostream &out, TClass *cl, const char *variable_name, const char *constructor_agrs = "", Bool_t empty_line = kTRUE);
static TString SavePrimitiveVector(std::ostream &out, const char *prefix, Int_t len, Double_t *arr, Int_t flag = 0);
static void SavePrimitiveDraw(std::ostream &out, const char *variable_name, Option_t *option = nullptr);
public:
//----- Global bits (can be set for any object and should not be reused).
//----- Bits 0 - 13 are reserved as global bits. Bits 14 - 23 can be used
//----- in different class hierarchies (make sure there is no overlap in
//----- any given hierarchy).
enum EStatusBits {
kCanDelete = BIT(0), ///< if object in a list can be deleted
// 2 is taken by TDataMember
kMustCleanup = BIT(3), ///< if object destructor must call RecursiveRemove()
kIsReferenced = BIT(4), ///< if object is referenced by a TRef or TRefArray
kHasUUID = BIT(5), ///< if object has a TUUID (its fUniqueID=UUIDNumber)
kCannotPick = BIT(6), ///< if object in a pad cannot be picked
// 7 is taken by TAxis and TClass.
kNoContextMenu = BIT(8), ///< if object does not want context menu
// 9, 10 are taken by TH1, TF1, TAxis and a few others
// 12 is taken by TAxis
kInvalidObject = BIT(13) ///< if object ctor succeeded but object should not be used
};
enum EDeprecatedStatusBits {
kObjInCanvas = BIT(3) ///< for backward compatibility only, use kMustCleanup
};
//----- Private bits, clients can only test but not change them
enum {
kIsOnHeap = 0x01000000, ///< object is on heap
kNotDeleted = 0x02000000, ///< object has not been deleted
kZombie = 0x04000000, ///< object ctor failed
kInconsistent = 0x08000000, ///< class overload Hash but does call RecursiveRemove in destructor
// kCheckedHash = 0x10000000, ///< CheckedHash has check for the consistency of Hash/RecursiveRemove
kBitMask = 0x00ffffff
};
//----- Write() options
enum {
kSingleKey = BIT(0), ///< write collection with single key
kOverwrite = BIT(1), ///< overwrite existing object with same name
kWriteDelete = BIT(2), ///< write object, then delete previous key with same name
};
protected:
enum { // DeprectatedWriteOptions
///< Used to request that the class specific implementation of `TObject::Write`
///< just prepare the objects to be ready to be written but do not actually write
///< them into the TBuffer. This is just for example by TBufferMerger to request
///< that the TTree inside the file calls `TTree::FlushBaskets` (outside of the merging lock)
///< and TBufferMerger will later ask for the write (inside the merging lock).
///< To take advantage of this feature the class needs to overload `TObject::Write`
///< and use this enum value accordingly. (See `TTree::Write` and `TObject::Write`)
///< Do not use, this feature will be migrate to the Merge function (See TClass and TTree::Merge)
kOnlyPrepStep = BIT(3)
};
public:
TObject();
TObject(const TObject &object) noexcept;
TObject &operator=(const TObject &rhs) noexcept;
virtual ~TObject();
virtual void AppendPad(Option_t *option="");
virtual void Browse(TBrowser *b);
virtual const char *ClassName() const;
virtual void Clear(Option_t * /*option*/ ="") { }
ULong_t CheckedHash(); // Not virtual
virtual TObject *Clone(const char *newname="") const;
virtual Int_t Compare(const TObject *obj) const;
virtual void Copy(TObject &object) const;
virtual void Delete(Option_t *option=""); // *MENU*
virtual Int_t DistancetoPrimitive(Int_t px, Int_t py);
virtual void Draw(Option_t *option="");
virtual void DrawClass() const; // *MENU*
virtual TObject *DrawClone(Option_t *option="") const; // *MENU*
virtual void Dump() const; // *MENU*
virtual void Execute(const char *method, const char *params, Int_t *error = nullptr);
virtual void Execute(TMethod *method, TObjArray *params, Int_t *error = nullptr);
virtual void ExecuteEvent(Int_t event, Int_t px, Int_t py);
virtual TObject *FindObject(const char *name) const;
virtual TObject *FindObject(const TObject *obj) const;
virtual Option_t *GetDrawOption() const;
virtual UInt_t GetUniqueID() const;
virtual const char *GetName() const;
virtual const char *GetIconName() const;
virtual Option_t *GetOption() const { return ""; }
virtual char *GetObjectInfo(Int_t px, Int_t py) const;
virtual const char *GetTitle() const;
virtual Bool_t HandleTimer(TTimer *timer);
Bool_t HasInconsistentHash() const;
virtual ULong_t Hash() const;
virtual Bool_t InheritsFrom(const char *classname) const;
virtual Bool_t InheritsFrom(const TClass *cl) const;
virtual void Inspect() const; // *MENU*
virtual Bool_t IsFolder() const;
virtual Bool_t IsEqual(const TObject *obj) const;
virtual Bool_t IsSortable() const { return kFALSE; }
R__ALWAYS_INLINE Bool_t IsOnHeap() const { return TestBit(kIsOnHeap); }
R__ALWAYS_INLINE Bool_t IsZombie() const { return TestBit(kZombie); }
virtual Bool_t Notify();
virtual void ls(Option_t *option="") const;
virtual void Paint(Option_t *option="");
virtual void Pop();
virtual void Print(Option_t *option="") const;
virtual Long64_t Read(const char *name);
virtual void RecursiveRemove(TObject *obj);
virtual void SaveAs(const char *filename="",Option_t *option="") const; // *MENU*
virtual void SavePrimitive(std::ostream &out, Option_t *option = "");
virtual void SetDrawOption(Option_t *option=""); // *MENU*
virtual void SetUniqueID(UInt_t uid);
virtual void UseCurrentStyle();
virtual Long64_t Write(const char *name = nullptr, Int_t option = 0, Long64_t bufsize = 0);
virtual Long64_t Write(const char *name = nullptr, Int_t option = 0, Long64_t bufsize = 0) const;
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Woverloaded-virtual"
#elif __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Woverloaded-virtual"
#endif
/// \deprecated Please override the `Long64_t` overload instead of the `Int_t` version.
[[deprecated]] virtual Long64_t Write(const char *name, Int_t option, Int_t bufsize) final
{ return Write(name, option, (Long64_t)bufsize); }
/// \deprecated Please override the `Long64_t` overload instead of the `Int_t` version.
[[deprecated]] virtual Long64_t Write(const char *name, Int_t option, Int_t bufsize) const final
{ return Write(name, option, (Long64_t)bufsize); }
#ifdef __clang__
#pragma clang diagnostic pop
#elif __GNUC__
#pragma GCC diagnostic pop
#endif
/// IsDestructed
///
/// \note This function must be non-virtual as it can be used on destructed (but
/// not yet modified) memory. This is used for example in TClonesArray to record
/// the element that have been destructed but not deleted and thus are ready for
/// re-use (by operator new with placement).
///
/// \return true if this object's destructor has been run.
Bool_t IsDestructed() const { return !TestBit(kNotDeleted); }
//----- operators
void *operator new(size_t sz) { return TStorage::ObjectAlloc(sz); }
void *operator new[](size_t sz) { return TStorage::ObjectAllocArray(sz); }
void *operator new(size_t sz, void *vp) { return TStorage::ObjectAlloc(sz, vp); }
void *operator new[](size_t sz, void *vp) { return TStorage::ObjectAlloc(sz, vp); }
void operator delete(void *ptr);
void operator delete[](void *ptr);
void operator delete(void*, size_t);
void operator delete[](void*, size_t);
void operator delete(void *ptr, void *vp);
void operator delete[](void *ptr, void *vp);
//----- bit manipulation
void SetBit(UInt_t f, Bool_t set);
void SetBit(UInt_t f) { fBits |= f & kBitMask; }
void ResetBit(UInt_t f) { fBits &= ~(f & kBitMask); }
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const { return (Bool_t) ((fBits & f) != 0); }
Int_t TestBits(UInt_t f) const { return (Int_t) (fBits & f); }
void InvertBit(UInt_t f) { fBits ^= f & kBitMask; }
//---- error handling
virtual void Info(const char *method, const char *msgfmt, ...) const
#if defined(__GNUC__)
__attribute__((format(printf, 3, 4))) /* 1 is the this pointer */
#endif
;
virtual void Warning(const char *method, const char *msgfmt, ...) const
#if defined(__GNUC__)
__attribute__((format(printf, 3, 4))) /* 1 is the this pointer */
#endif
;
virtual void Error(const char *method, const char *msgfmt, ...) const
#if defined(__GNUC__)
__attribute__((format(printf, 3, 4))) /* 1 is the this pointer */
#endif
;
virtual void SysError(const char *method, const char *msgfmt, ...) const
#if defined(__GNUC__)
__attribute__((format(printf, 3, 4))) /* 1 is the this pointer */
#endif
;
virtual void Fatal(const char *method, const char *msgfmt, ...) const
#if defined(__GNUC__)
__attribute__((format(printf, 3, 4))) /* 1 is the this pointer */
#endif
;
void AbstractMethod(const char *method) const;
void MayNotUse(const char *method) const;
void Obsolete(const char *method, const char *asOfVers, const char *removedFromVers) const;
//---- static functions
static Longptr_t GetDtorOnly();
static void SetDtorOnly(void *obj);
static Bool_t GetObjectStat();
static void SetObjectStat(Bool_t stat);
friend class TClonesArray; // needs to reset kNotDeleted in fBits
friend bool ROOT::Internal::DeleteChangesMemoryImpl();
ClassDef(TObject,1) //Basic ROOT object
};
////////////////////////////////////////////////////////////////////////////////
/// TObject constructor. It sets the two data words of TObject to their
/// initial values. The unique ID is set to 0 and the status word is
/// set depending if the object is created on the stack or allocated
/// on the heap. Depending on the ROOT environment variable "Root.ObjStat"
/// (see TEnv) the object is added to the global TObjectTable for
/// bookkeeping.
inline TObject::TObject() : fBits(kNotDeleted) // Need to leave fUniqueID unset
{
// This will be reported by valgrind as uninitialized memory reads for
// object created on the stack, use $ROOTSYS/etc/valgrind-root.supp
TStorage::UpdateIsOnHeap(fUniqueID, fBits);
fUniqueID = 0;
#ifdef R__WIN32
if (R__unlikely(GetObjectStat())) TObject::AddToTObjectTable(this);
#else
if (R__unlikely(fgObjectStat)) TObject::AddToTObjectTable(this);
#endif
}
////////////////////////////////////////////////////////////////////////////////
/// TObject copy ctor.
inline TObject::TObject(const TObject &obj) noexcept
{
fBits = obj.fBits;
// This will be reported by valgrind as uninitialized memory reads for
// object created on the stack, use $ROOTSYS/etc/valgrind-root.supp
TStorage::UpdateIsOnHeap(fUniqueID, fBits);
fBits &= ~kIsReferenced;
fBits &= ~kCanDelete;
// Set only after used in above call
fUniqueID = obj.fUniqueID; // when really unique don't copy
#ifdef R__WIN32
if (R__unlikely(GetObjectStat())) TObject::AddToTObjectTable(this);
#else
if (R__unlikely(fgObjectStat)) TObject::AddToTObjectTable(this);
#endif
}
////////////////////////////////////////////////////////////////////////////////
/// TObject assignment operator.
inline TObject &TObject::operator=(const TObject &rhs) noexcept
{
if (R__likely(this != &rhs)) {
fUniqueID = rhs.fUniqueID; // when really unique don't copy
if (IsOnHeap()) { // test uses fBits so don't move next line
fBits = rhs.fBits;
fBits |= kIsOnHeap;
} else {
fBits = rhs.fBits;
fBits &= ~kIsOnHeap;
}
fBits &= ~kIsReferenced;
fBits &= ~kCanDelete;
}
return *this;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief Check and record whether this class has a consistent
/// Hash/RecursiveRemove setup (*) and then return the regular Hash value for
/// this object. The intent is for this routine to be called instead of directly
/// calling the function Hash during "insert" operations. See TObject::HasInconsistenTObjectHash();
///
/// (*) The setup is consistent when all classes in the class hierarchy that overload
/// TObject::Hash do call ROOT::CallRecursiveRemoveIfNeeded in their destructor.
/// i.e. it is safe to call the Hash virtual function during the RecursiveRemove operation.
inline ULong_t TObject::CheckedHash()
{
// Testing and recording whether we already called HasInconstistentTObjectHash
// for this object could save some cpu cycles in some circuntances (at the cost
// of reserving yet another bit).
// For each insert (CheckedHash is called only for insert in THashList/THashTable), it
// cost one memory fetch, one arithmetic operation and one branching.
// This save a virtual function call which itself contains a static variable memory
// fetch, a branching (of whether the static was already set or not).
// Given that a virtual function call is essentially 2 memory fetches (virtual table
// location and then content), one arithmetic operation and one function call/jump),
// we guess-estimate that the version recording-then-testing-prior-check would start
// saving cpu cycle when each object is inserted in average 1.5 times in a THashList/THashTable.
// if ( !fBits & kCheckedHash) {
if (!CheckTObjectHashConsistency())
fBits |= kInconsistent;
// fBits &= kChecked;
//}
return Hash();
}
////////////////////////////////////////////////////////////////////////////////
/// @brief Return true is the type of this object is *known* to have an
/// inconsistent setup for Hash and RecursiveRemove (i.e. missing call to
/// RecursiveRemove in destructor).
///
/// Note: Since the consistency is only tested for during inserts, this
/// routine will return true for object that have never been inserted
/// whether or not they have a consistent setup. This has no negative
/// side-effect as searching for the object with the right or wrong
/// Hash will always yield a not-found answer (Since anyway no hash
/// can be guaranteed unique, there is always a check)
inline Bool_t TObject::HasInconsistentHash() const
{
return fBits & kInconsistent;
}
// Global bits (can be set for any object and should not be reused).
// Only here for backward compatibility reasons.
// For detailed description see TObject::EStatusBits above.
enum EObjBits {
kCanDelete = TObject::kCanDelete,
kMustCleanup = TObject::kMustCleanup,
kObjInCanvas = TObject::kObjInCanvas,
kIsReferenced = TObject::kIsReferenced,
kHasUUID = TObject::kHasUUID,
kCannotPick = TObject::kCannotPick,
kNoContextMenu = TObject::kNoContextMenu,
kInvalidObject = TObject::kInvalidObject
};
namespace cling {
std::string printValue(TObject *val);
}
namespace ROOT {
namespace Internal {
bool DeleteChangesMemory();
} // Internal
namespace Detail {
/// @brief Check if the TObject's memory has been deleted.
/// @warning This should be only used for error mitigation as the answer is only
/// sometimes correct. It actually just checks whether the object has been
/// deleted, so this will falsely return true for an object that has
/// been destructed but its memory has not been deleted. This will return an
/// undefined value if the memory is re-used between the deletion and the check.
/// i.e. This is useful to prevent a segmentation fault in case where the problem
/// can be detected when the deletion and the usage are 'close-by'
/// @warning In enviroment where delete taints (changes) the memory, this function
/// always returns false as the marker left by ~TObject will be overwritten.
/// @param obj The memory to check
/// @return true if the object has been destructed and it can be inferred that it has been deleted
R__ALWAYS_INLINE bool HasBeenDeleted(const TObject *obj) {
return !ROOT::Internal::DeleteChangesMemory() && obj->IsDestructed();
}
}} // ROOT::Details
#endif