Logo ROOT  
Reference Guide
Loading...
Searching...
No Matches
rootclingIO.cxx
Go to the documentation of this file.
1// @(#)root/utils:$Id$
2// Author: Axel Naumann, 2014-04-07
3
4/*************************************************************************
5 * Copyright (C) 1995-2014, 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// Provides bindings to TCling (compiled with rtti) from rootcling (compiled
13// without rtti).
14
15#include "TClass.h"
16#include "TEnum.h"
17#include "TError.h"
18#include "TFile.h"
19#include "TProtoClass.h"
20#include "TDataMember.h"
21#include "TROOT.h"
22#include "TStreamerInfo.h"
23#include "TClassEdit.h"
24
25#include <algorithm>
26#include <memory>
27
28std::string gPCMFilename;
29std::vector<std::string> gClassesToStore;
30std::vector<std::string> gTypedefsToStore;
31std::vector<std::string> gEnumsToStore;
32
33extern "C"
38
39extern "C"
40void AddStreamerInfoToROOTFile(const char *normName)
41{
42 // Filter unnamed and (anonymous) classes.
43 if (normName && normName[0] && normName[0] != '(')
44 gClassesToStore.emplace_back(normName);
45}
46
47extern "C"
48void AddTypedefToROOTFile(const char *tdname)
49{
50 gTypedefsToStore.emplace_back(tdname);
51}
52
53extern "C"
54void AddEnumToROOTFile(const char *enumname)
55{
56 gEnumsToStore.emplace_back(enumname);
57}
58
60{
61 auto regularPtr = (long *)0x42;
62 std::unique_ptr<long> uniquePtr(regularPtr);
63 auto regularPtr_2 = reinterpret_cast<long **>(&uniquePtr);
64 bool isZero = uniquePtr.get() == *regularPtr_2;
65 uniquePtr.release();
66 if (!isZero) {
67 Error("CloseStreamerInfoROOTFile",
68 "UniquePtr points to %p, reinterpreting it gives %p and should have %p", uniquePtr.get(), *(regularPtr_2), regularPtr);
69 }
70 return isZero;
71}
72
73static bool IsUnsupportedUniquePointer(const char *normName, TDataMember *dm)
74{
75 auto dmTypeName = dm->GetTypeName();
76 static bool isUniquePtrOffsetZero = IsUniquePtrOffsetZero(); // call this only once
77 if (TClassEdit::IsUniquePtr(dmTypeName)) {
78
79 if (!isUniquePtrOffsetZero) return true;
80
81 // We check if the unique_ptr has a default deleter
82 std::vector<std::string> out;
83 int i;
84 TClassEdit::GetSplit(dmTypeName, out, i);
85 // out[2] contains the deleter type.
86 if (0 != out[2].find("default_delete<")) {
87 Error("CloseStreamerInfoROOTFile", "I/O is supported only for unique_ptrs with a default deleter. %s::%s appears to have a custom one, %s.", normName, dm->GetName(), out[2].c_str());
88 return true;
89 }
90 }
91 return false;
92}
93
94// static bool IsSupportedClass(TClass *cl)
95// {
96// // Check if the Class is of an unsupported type
97// using namespace ROOT::TMetaUtils;
98//
99// // Check if this is a collection of unique_ptrs
100// if (ROOT::ESTLType::kNotSTL != cl->GetCollectionType()) {
101// std::vector<std::string> out;
102// int i;
103// TClassEdit::GetSplit(cl->GetName(), out, i);
104// std::string_view containedObjectTypeName(out[1].c_str());
105// if (TClassEdit::IsUniquePtr(containedObjectTypeName)) {
106// auto clName = cl->GetName();
107// // Here we can use the new name for the error message
108// Error("CloseStreamerInfoROOTFile", "A collection of unique pointers was selected: %s. These are not supported. If you wish to perform I/O operations with %s, just select the same collection of raw C pointers.\n", clName, clName);
109// return false;
110// }
111// }
112// return true;
113//
114// }
115
116extern "C"
117bool CloseStreamerInfoROOTFile(bool writeEmptyRootPCM)
118{
119 // Write all persistent TClasses.
120
121 // Avoid plugins.
123
124 // Don't use TFile::Open(); we don't need plugins.
125 TFile dictFile((gPCMFilename + "?filetype=pcm").c_str(), "RECREATE");
126
127 // Reset the content of the pcm
128 if (writeEmptyRootPCM) {
129 TObject obj;
130 obj.Write("EMPTY");
131 return true;
132 };
133
134 TObjArray protoClasses(gClassesToStore.size());
135 for (const auto & normName : gClassesToStore) {
136 TClass *cl = TClass::GetClass(normName.c_str(), kTRUE /*load*/);
137 if (!cl) {
138 Error("CloseStreamerInfoROOTFile", "Cannot find class %s.", normName.c_str());
139 return false;
140 }
141
142// if (!IsSupportedClass(cl)) return false;
143
144 // Check if a datamember is a unique_ptr and if yes that it has a default
145 // deleter.
146 auto dms = cl->GetListOfDataMembers();
147 if (!dms) {
148 Error("CloseStreamerInfoROOTFile", "Cannot find data members for %s.", normName.c_str());
149 return false;
150 }
151
152 for (auto dmObj : *dms) {
153 auto dm = (TDataMember *) dmObj;
154 if (!dm->IsPersistent() || cl->GetClassVersion()==0) continue;
155 if (IsUnsupportedUniquePointer(normName.c_str(), dm)) return false;
156 if (dm->IsEnum()) {
157 const char *enumTypeName = dm->GetTypeName();
158 auto enumType = TEnum::GetEnum(enumTypeName);
159 if (enumType && (!enumType->GetClass() || !enumType->GetClass()->IsLoaded()) &&
160 ((strstr(enumTypeName, "(unnamed)") == nullptr) &&
161 std::find(gEnumsToStore.begin(), gEnumsToStore.end(), enumTypeName) == gEnumsToStore.end()))
162 gEnumsToStore.emplace_back(enumTypeName);
163 }
164
165 }
166
167 // Never store a proto class for a class which rootcling already has
168 // an 'official' TClass (i.e. the dictionary is in libCore or libRIO).
169 if (cl->IsLoaded()) continue;
170
171 // We include transient classes as they could be used by a derived
172 // class which may have rules setting the member of the transient class.
173 // (And the derived class RealData *do* contain member from the transient
174 // base classes.
175// if (cl->GetClassVersion() == 0)
176// continue;
177
178 // Let's include also proxied collections in order to delay parsing as long as possible.
179 // In the first implementations, proxied collections did not result in a protoclass.
180 // If this is a proxied collection then offsets are not needed.
181// if (cl->GetCollectionProxy())
182// continue;
183 cl->Property(); // Force initialization of the bits and property fields.
184
185 if (auto pr = cl->GetCollectionProxy()) {
186 auto colltype = pr->GetCollectionType();
187 if (colltype == ROOT::kSTLmap || colltype == ROOT::kSTLmultimap ||
188 colltype == ROOT::kSTLunorderedmap || colltype == ROOT::kSTLunorderedmultimap) {
189 if (auto pcl = pr->GetValueClass()) {
190 if (auto pcl_dms = pcl->GetListOfDataMembers()) {
191 for (auto dmObj : *pcl_dms) {
192 auto dm = (TDataMember *) dmObj;
193 if (dm->IsEnum()) {
194 const char *enumTypeName = dm->GetTypeName();
195 auto enumType = TEnum::GetEnum(enumTypeName);
196 if (enumType && (!enumType->GetClass() || !enumType->GetClass()->IsLoaded()) &&
197 (std::find(gEnumsToStore.begin(), gEnumsToStore.end(), enumTypeName) == gEnumsToStore.end()))
198 gEnumsToStore.emplace_back(enumTypeName);
199 }
200 }
201 }
202 }
203 }
204 }
205
206 protoClasses.AddLast(new TProtoClass(cl));
207 }
208
209 TObjArray typedefs(gTypedefsToStore.size());
210
211 for (const auto & dtname : gTypedefsToStore) {
212 TDataType *dt = (TDataType *)gROOT->GetListOfTypes()->FindObject(dtname.c_str());
213 if (!dt) {
214 Error("CloseStreamerInfoROOTFile", "Cannot find typedef %s.", dtname.c_str());
215 return false;
216 }
217 if (dt->GetType() == -1) {
218 dt->Property(); // Force initialization of the bits and property fields.
219 dt->GetTypeName(); // Force caching of type name.
220 typedefs.AddLast(dt);
221 }
222 }
223
224
225 TObjArray enums(gEnumsToStore.size());
226 for (const auto & enumname : gEnumsToStore) {
227 TEnum *en = nullptr;
228 const size_t lastSepPos = enumname.rfind("::");
229 if (lastSepPos != std::string::npos) {
230 const std::string nsName = enumname.substr(0, lastSepPos);
231 TClass *tclassInstance = TClass::GetClass(nsName.c_str());
232 if (!tclassInstance) {
233 Error("CloseStreamerInfoROOTFile", "Cannot find TClass instance for namespace %s.", nsName.c_str());
234 return false;
235 }
236 if (!(tclassInstance->Property() & kIsNamespace))
237 continue; // Enum will be part of the TClass.
238 auto enumListPtr = tclassInstance->GetListOfEnums();
239 if (!enumListPtr) {
240 Error("CloseStreamerInfoROOTFile", "TClass instance for namespace %s does not have any enum associated. This is an inconsistency.", nsName.c_str());
241 return false;
242 }
243 const std::string unqualifiedEnumName = enumname.substr(lastSepPos + 2);
244 en = (TEnum *)enumListPtr->FindObject(unqualifiedEnumName.c_str());
245 if (en) en->SetTitle(nsName.c_str());
246 } else {
247 en = (TEnum *)gROOT->GetListOfEnums()->FindObject(enumname.c_str());
248 if (en) en->SetTitle("");
249 }
250 if (!en) {
251 Error("CloseStreamerInfoROOTFile", "Cannot find enum %s.", enumname.c_str());
252 return false;
253 }
254 en->Property(); // Force initialization of the bits and property fields.
255 enums.AddLast(en);
256 }
257
258 if (dictFile.IsZombie())
259 return false;
260// Instead of plugins:
261 typedefs.Write("__Typedefs", TObject::kSingleKey);
262 enums.Write("__Enums", TObject::kSingleKey);
263 protoClasses.Write("__ProtoClasses", TObject::kSingleKey);
264 protoClasses.Delete();
265
266 return true;
267}
constexpr Bool_t kTRUE
Definition RtypesCore.h:107
@ kIsNamespace
Definition TDictionary.h:95
Error("WriteTObject","The current directory (%s) is not associated with a file. The object (%s) has not been written.", GetName(), objname)
#define gROOT
Definition TROOT.h:417
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:84
TList * GetListOfEnums(Bool_t load=kTRUE)
Return a list containing the TEnums of a class.
Definition TClass.cxx:3744
Long_t Property() const override
Returns the properties of the TClass as a bit field stored as a Long_t value.
Definition TClass.cxx:6191
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:2994
Int_t Write(const char *name=nullptr, Int_t option=0, Int_t bufsize=0) override
Write all objects in this collection.
All ROOT classes may have RTTI (run time type identification) support added.
Definition TDataMember.h:31
Basic data type descriptor (datatype information is obtained from CINT).
Definition TDataType.h:44
The TEnum class implements the enum type.
Definition TEnum.h:33
Long_t Property() const override
Get property description word. For meaning of bits see EProperty.
Definition TEnum.cxx:141
static TEnum * GetEnum(const std::type_info &ti, ESearchAction sa=kALoadAndInterpLookup)
Definition TEnum.cxx:181
A file, usually with extension .root, that stores data and code in the form of serialized objects in ...
Definition TFile.h:130
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
Definition TNamed.cxx:173
An array of TObjects.
Definition TObjArray.h:31
void Delete(Option_t *option="") override
Remove all objects from the array AND delete all heap based objects.
void AddLast(TObject *obj) override
Add object in the next empty slot in the array.
Mother of all ROOT objects.
Definition TObject.h:42
virtual TObject * FindObject(const char *name) const
Must be redefined in derived classes.
Definition TObject.cxx:425
@ kSingleKey
write collection with single key
Definition TObject.h:100
Bool_t IsZombie() const
Definition TObject.h:161
Persistent version of a TClass.
Definition TProtoClass.h:38
Describes a persistent version of a class.
static void SetFactory(TVirtualStreamerInfo *factory)
static function: Set the StreamerInfo factory
auto filename
@ kSTLmap
Definition ESTLType.h:33
@ kSTLunorderedmultimap
Definition ESTLType.h:45
@ kSTLunorderedmap
Definition ESTLType.h:44
@ kSTLmultimap
Definition ESTLType.h:34
int GetSplit(const char *type, std::vector< std::string > &output, int &nestedLoc, EModType mode=TClassEdit::kNone)
Stores in output (after emptying it) the split type.
bool IsUniquePtr(std::string_view name)
Definition TClassEdit.h:229
void pr(register struct inclist *ip, char *file, char *base, char *dep)
Definition pr.c:86
static bool IsUnsupportedUniquePointer(const char *normName, TDataMember *dm)
void AddTypedefToROOTFile(const char *tdname)
bool CloseStreamerInfoROOTFile(bool writeEmptyRootPCM)
std::vector< std::string > gEnumsToStore
void AddEnumToROOTFile(const char *enumname)
void InitializeStreamerInfoROOTFile(const char *filename)
void AddStreamerInfoToROOTFile(const char *normName)
std::vector< std::string > gTypedefsToStore
std::string gPCMFilename
static bool IsUniquePtrOffsetZero()
std::vector< std::string > gClassesToStore