Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TStatusBitsChecker.cxx
Go to the documentation of this file.
1// Author: Philippe Canal, 2017
2
3/*************************************************************************
4 * Copyright (C) 1995-2017, Rene Brun and Fons Rademakers. *
5 * All rights reserved. *
6 * *
7 * For the licensing terms see $ROOTSYS/LICENSE. *
8 * For the list of contributors see $ROOTSYS/README/CREDITS. *
9 *************************************************************************/
10
11/** \class TStatusBitsChecker
12
13 TStatusBitsChecker::Check and TStatusBitsChecker::CheckAllClasses will
14 determine if the set of "status bit" declared in the class and its
15 base classes presents any overlap. The status bit are declared in
16 a given class by declaring an enum type named EStatusBits.
17 If some of the duplication is intentional, those duplication can
18 be registered in an enum type named EStatusBitsDupExceptions.
19
20 ~~~ {.cpp}
21 // TStreamerElement status bits
22 enum EStatusBits {
23 kHasRange = BIT(6),
24 kCache = BIT(9),
25 kRepeat = BIT(10),
26 kRead = BIT(11),
27 kWrite = BIT(12),
28 kDoNotDelete = BIT(13),
29 kWholeObject = BIT(14)
30 };
31
32 enum class EStatusBitsDupExceptions {
33 // This bit duplicates TObject::kInvalidObject. As the semantic of kDoNotDelete is a persistent,
34 // we can not change its value without breaking forward compatibility.
35 // Furthermore, TObject::kInvalidObject and its semantic is not (and should not be)
36 // used in TStreamerElement
37 kDoNotDelete = TStreamerElement::kDoNotDelete,
38
39 // This bit duplicates TObject::kCannotPick. As the semantic of kHasRange is a persistent,
40 // we can not change its value without breaking forward compatibility.
41 // Furthermore, TObject::kCannotPick and its semantic is not (and should not be)
42 // used in TStreamerElement
43 kHasRange = TStreamerElement::kHasRange
44 };
45 ~~~ {.cpp}
46
47 Without the EStatusBitsDupExceptions enum you would see
48
49 ~~~ {.cpp}
50TStatusBitsChecker::Check("TStreamerElement");
51
52Error in <TStatusBitsChecker>: In TStreamerElement class hierarchy, there are duplicates bits:
53Error in <TStatusBitsChecker>: Bit 6 used in TStreamerElement as kHasRange
54Error in <TStatusBitsChecker>: Bit 6 used in TObject as kCannotPick
55Error in <TStatusBitsChecker>: Bit 13 used in TStreamerElement as kDoNotDelete
56Error in <TStatusBitsChecker>: Bit 13 used in TObject as kInvalidObject
57 ~~~ {.cpp}
58
59*/
60
61#include "TStatusBitsChecker.h"
62
63#include "TBaseClass.h"
64#include "TClass.h"
65#include "TClassTable.h"
66#include "TEnum.h"
67#include "TEnumConstant.h"
68#include "TError.h"
69
70#include <cmath>
71#include <set>
72
73namespace ROOT {
74namespace Detail {
75
76struct TStatusBitsChecker::Registry::Info {
77 Info() = default;
78 Info(const Info &) = default;
79 Info(Info &&) = default;
80
81 Info(TClass &o, std::string &&n, bool intentionalDup) : fOwner(&o), fConstantName(n), fIntentionalDup(intentionalDup)
82 {
83 }
84
85 ~Info() = default;
86
87 TClass *fOwner;
88 std::string fConstantName;
89 bool fIntentionalDup = false;
90};
91
92/// Default constructor. Implemented in source file to allow hiding of the Info struct.
94
95/// Default destructor. Implemented in source file to allow hiding of the Info struct.
97
98/// Figure out which bit the constant has been set from/to.
99/// Return 255 if the constant is not an integer or out of range.
100UChar_t TStatusBitsChecker::ConvertToBit(Long64_t constant, TClass &classRef, const char *constantName)
101{
102
103 if (constant <= 0) {
104 Error("TStatusBitsChecker::ConvertBit", "In %s the value of %s is %lld which was not produced by BIT macro.",
105 classRef.GetName(), constantName, constant);
106 return 255;
107 }
108
109 int backshift;
110 double fraction = std::frexp(constant, &backshift);
111 // frexp doc is:
112 // if no errors occur,
113 // returns the value x in the range (-1;-0.5], [0.5; 1)
114 // and stores an integer value in *exp such that x×2^(*exp) = arg
115 --backshift; // frexp is such that BIT(0) == 1 == 0.5*2^(*exp) with *exp == 1
116
117 if (backshift < 0 || std::abs(0.5 - fraction) > 0.00001f) {
118 Error("TStatusBitsChecker::ConvertBit", "In %s the value of %s is %lld which was not produced by BIT macro.",
119 classRef.GetName(), constantName, constant);
120 return 255;
121 }
122
123 if (backshift > 24) {
124 Error("TStatusBitsChecker::ConvertBit", "In %s the value of %s is %lld (>23) which is ignored by SetBit.",
125 classRef.GetName(), constantName, constant);
126
127 if (backshift > 255) // really we could snip it sooner.
128 backshift = 255;
129 }
130
131 return backshift;
132}
133
134/// @brief Add to fRegister the Info about the bits in this class and its base
135/// classes.
137{
138 TEnum *eStatusBits = (TEnum *)classRef.GetListOfEnums()->FindObject("EStatusBits");
139 TEnum *exceptionBits = (TEnum *)classRef.GetListOfEnums()->FindObject("EStatusBitsDupExceptions");
140
141 if (eStatusBits) {
142
143 for (auto constant : TRangeStaticCast<TEnumConstant>(*eStatusBits->GetConstants())) {
144
145 // Ignore the known/intentional duplication.
146 bool intentionalDup = exceptionBits && exceptionBits->GetConstant(constant->GetName());
147
148 auto value = constant->GetValue();
149 auto bit = ConvertToBit(value, classRef, constant->GetName());
150
151 if (bit < 24) {
152 bool need = true;
153 for (auto reg : fRegister[bit]) {
154 if (reg.fOwner == &classRef) {
155 // We have a duplicate declared in the same class
156 // let's accept this as an alias.
157 need = false;
158 }
159 }
160
161 if (need)
162 fRegister[bit].emplace_back(classRef, std::string(constant->GetName()), intentionalDup);
163 }
164 }
165 }
166
167 TList *lb = classRef.GetListOfBases();
168 if (lb) {
169 for (auto base : TRangeStaticCast<TBaseClass>(*lb)) {
170 TClass *bcl = base->GetClassPointer();
171 if (bcl)
172 RegisterBits(*bcl);
173 }
174 }
175}
176
177/// @brief Return false and print error messages if there is any unexpected
178/// duplicates BIT constant in the class hierarchy or any of the bits
179/// already registered.
180/// If verbose is true, also print all the bit declare in this class
181/// and all its bases.
182bool TStatusBitsChecker::Registry::Check(TClass &classRef, bool verbose /* = false */)
183{
184 RegisterBits(classRef);
185
186 if (verbose) {
187 for (auto cursor : fRegister) {
188 for (auto constant : cursor.second) {
189 Printf("Bit %3d declared in %s as %s", cursor.first, constant.fOwner->GetName(),
190 constant.fConstantName.c_str());
191 }
192 }
193 }
194
195 bool issuedHeader = false;
196 bool result = true;
197 for (auto cursor : fRegister) {
198 unsigned int nDuplicate = 0;
199 for (auto constant : cursor.second) {
200 if (!constant.fIntentionalDup)
201 ++nDuplicate;
202 }
203 if (nDuplicate > 1) {
204 if (!issuedHeader) {
205 Error("TStatusBitsChecker", "In %s class hierarchy, there are duplicates bits:", classRef.GetName());
206 issuedHeader = true;
207 }
208 for (auto constant : cursor.second) {
209 if (!constant.fIntentionalDup) {
210 Error("TStatusBitsChecker", " Bit %3d used in %s as %s", cursor.first, constant.fOwner->GetName(),
211 constant.fConstantName.c_str());
212 result = false;
213 }
214 }
215 }
216 }
217
218 return result;
219}
220
221/// Return false and print error messages if there is any unexpected
222/// duplicates BIT constant in the class hierarchy.
223/// If verbose is true, also print all the bit declare in this class
224/// and all its bases.
225bool TStatusBitsChecker::Check(TClass &classRef, bool verbose /* = false */)
226{
227 return Registry().Check(classRef, verbose);
228}
229
230/// Return false and print error messages if there is any unexpected
231/// duplicates BIT constant in the class hierarchy.
232/// If verbose is true, also print all the bit declare in this class
233/// and all its bases.
234bool TStatusBitsChecker::Check(const char *classname, bool verbose)
235{
236 TClass *cl = TClass::GetClass(classname);
237 if (cl)
238 return Check(*cl, verbose);
239 else
240 return true;
241}
242
243/// Return false and print error messages if there is any unexpected
244/// duplicates BIT constant in any of the class hierarchy knows
245/// to TClassTable.
246/// If verbose is true, also print all the bit declare in eacho of the classes
247/// and all their bases.
248bool TStatusBitsChecker::CheckAllClasses(bool verbosity /* = false */)
249{
250 bool result = true;
251
252 // Start from beginning
253 gClassTable->Init();
254
255 std::set<std::string> rootLibs;
256 TList classesDeclFileNotFound;
257 TList classesImplFileNotFound;
258
259 Int_t totalNumberOfClasses = gClassTable->Classes();
260 for (Int_t i = 0; i < totalNumberOfClasses; i++) {
261
262 // get class name
263 const char *cname = gClassTable->Next();
264 if (!cname)
265 continue;
266
267 // get class & filename - use TROOT::GetClass, as we also
268 // want those classes without decl file name!
269 TClass *classPtr = TClass::GetClass((const char *)cname, kTRUE);
270 if (!classPtr)
271 continue;
272
273 result = Check(*classPtr, verbosity) && result;
274 }
275
276 return result;
277}
278
279} // namespace Detail
280} // namespace ROOT
unsigned char UChar_t
Definition RtypesCore.h:38
long long Long64_t
Definition RtypesCore.h:73
const Bool_t kTRUE
Definition RtypesCore.h:91
R__EXTERN TClassTable * gClassTable
Definition TClassTable.h:95
void Info(const char *location, const char *msgfmt,...)
Use this function for informational messages.
Definition TError.cxx:220
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition TError.cxx:187
void Printf(const char *fmt,...)
TRangeStaticCast is an adaptater class that allows the typed iteration through a TCollection.
std::map< UChar_t, std::list< Info > > fRegister
! Register of bits seen so far.
Registry()
Default constructor. Implemented in source file to allow hiding of the Info struct.
bool Check(TClass &classRef, bool verbose=false)
Return false and print error messages if there is any unexpected duplicates BIT constant in the class...
void RegisterBits(TClass &classRef)
Add to fRegister the Info about the bits in this class and its base classes.
~Registry()
Default destructor. Implemented in source file to allow hiding of the Info struct.
static bool Check(TClass &classRef, bool verbose=false)
Return false and print error messages if there is any unexpected duplicates BIT constant in the class...
static UChar_t ConvertToBit(Long64_t constant, TClass &classRef, const char *constantName)
Figure out which bit the constant has been set from/to.
static bool CheckAllClasses(bool verbosity=false)
Return false and print error messages if there is any unexpected duplicates BIT constant in any of th...
static char * Next()
Returns next class from sorted class table.
static void Init()
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:80
TList * GetListOfEnums(Bool_t load=kTRUE)
Return a list containing the TEnums of a class.
Definition TClass.cxx:3663
TList * GetListOfBases()
Return list containing the TBaseClass(es) of a class.
Definition TClass.cxx:3613
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition TClass.cxx:2957
Long64_t GetValue() const
The TEnum class implements the enum type.
Definition TEnum.h:33
const TSeqCollection * GetConstants() const
Definition TEnum.h:60
const TEnumConstant * GetConstant(const char *name) const
Definition TEnum.h:61
A doubly linked list.
Definition TList.h:44
virtual TObject * FindObject(const char *name) const
Find an object in this list using its name.
Definition TList.cxx:578
virtual const char * GetName() const
Returns name of object.
Definition TNamed.h:47
const Int_t n
Definition legend1.C:16
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...