REST-for-Physics  v2.3
Rare Event Searches ToolKit for Physics
TRestReflector.cxx
1#include "TRestReflector.h"
2
3#include "TEmulatedCollectionProxy.h"
4#include "TRestStringHelper.h"
5#include "TRestTools.h"
6#include "TStreamerInfo.h"
7#include "TSystem.h"
8
9using namespace std;
10
11namespace REST_Reflection {
57TRestReflector::TRestReflector(void* _address, const string& _type) {
58 address = (char*)_address;
59 onheap = false;
60 cl = GetClassQuick(_type);
61 DataType_Info dt = DataType_Info(_type);
62 if (cl == nullptr && dt.size == 0) {
63 cout << "In TRestReflector::TRestReflector() : unrecognized type: \"" << _type << "\"" << endl;
64 return;
65 }
66
67 typeinfo = cl == 0 ? dt.typeinfo : cl->GetTypeInfo();
68 is_data_type = dt.size > 0;
69 size = cl == 0 ? dt.size : cl->Size();
70 type = cl == 0 ? dt.name : cl->GetName();
71
73}
74
76 if (!IsZombie() && onheap) {
77 Destroy();
78 }
79
80 if (cl != nullptr) {
81 address = (char*)cl->New();
82 onheap = true;
83 } else if (is_data_type) {
84 address = (char*)malloc(size);
85 memset(address, 0, size);
86 onheap = true;
87 }
88}
89
91 if (address == nullptr) return;
92 if (onheap == false) {
93 // It can only delete/free objects on heap memory
94 cout << "In TRestReflector::Destroy() : cannot free on stack memory!" << endl;
95 return;
96 }
97
98 if (cl != nullptr) {
99 cl->Destructor(address);
100 } else if (is_data_type) {
101 free(address);
102 }
103}
104
105void TRestReflector::PrintMemory(int bytepreline) {
106 if (!IsZombie()) {
107 int i = 0;
108 while (i < size) {
109 stringstream save;
110 for (unsigned char j = 0; j < bytepreline && i < size; j++) {
111 // 44 03 00 d1 56 00 00 05 00 16 60 4a 38 08 81 8e
112 // 44 03 00 D1 56 00 00 05 00 16 60 4A 38 08 81 8E
113 save << std::uppercase << std::setfill('0') << std::setw(2) << std::hex
114 << ((*(address + i)) & 0xff) << " ";
115 i++;
116 }
117 cout << save.str() << endl;
118 }
119 }
120}
121
123
125 if (type == "string") return *(string*)(address);
126 if (address == nullptr) return "null";
127 RESTVirtualConverter* converter = RESTConverterMethodBase[typeinfo->hash_code()];
128 if (converter != nullptr) {
129 return converter->ToString(address);
130 } else {
131 return Form("Type: %s, Address: %p", type.c_str(), address);
132 }
133}
134
136 if (type == "string") {
137 *(string*)(address) = str;
138 } else {
139 RESTVirtualConverter* converter = RESTConverterMethodBase[typeinfo->hash_code()];
140 if (converter != nullptr) {
141 converter->ParseString(address, str);
142 } else {
143 cout << "Method for parsing string to " << type << " has not been registered!" << endl;
144 }
145 }
146}
147
149 if (is_data_type) return 0;
150
151 if (cl != nullptr) {
152 if (cl->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(cl->GetCollectionProxy())) {
153 // cout << "In TRestReflector::CloneTo() : the target is an stl collection but does not have a "
154 // "compiled CollectionProxy. Please generate the dictionary for this collection."
155 // << endl;
156 // cout << "Data not copied!" << endl;
157 } else {
158 return 0;
159 }
160 }
161
162 if (type == "" || size == 0 || cl == nullptr) {
163 cout << "Error in CreateDictionary: object is zombie!" << endl;
164 return -1;
165 }
166
167 int pos = ((string)type).find("<");
168
169 string basetype = ((string)type).substr(0, pos);
170 vector<string> stltypes{"vector", "list", "map", "set", "array", "deque"};
171 bool flag = false;
172 for (auto stltype : stltypes) {
173 if (basetype == stltype) {
174 flag = true;
175 }
176 }
177 if (!flag) {
178 cout << "Error in CreateDictionary: unknown type \"" << type << "\"" << endl;
179 return -1;
180 }
181
182 string typeformatted = Replace(type, ">", "_");
183 typeformatted = Replace(typeformatted, "<", "_");
184 typeformatted = Replace(typeformatted, ",", "_");
185 typeformatted = RemoveWhiteSpaces(typeformatted);
186
187 string sofilename = REST_USER_PATH + (string) "/AddonDict/Dict_" + typeformatted + ".so";
188
189 // we directly load the dictionary if it exists
190 if (TRestTools::fileExists(sofilename)) {
191 cout << "Loading external dictionary for: \"" << type << "\":" << endl;
192 cout << sofilename << endl;
193
194 } else {
195 // we create a new library of dictionary for that type
196 if (!TRestTools::isPathWritable(REST_USER_PATH)) {
197 cout << "Error in CreateDictionary: cannot create dictionary, path not writeable!" << endl;
198 cout << "path: \"" << REST_USER_PATH << "\"" << endl;
199 cout << "This is possible in case you are using public installation of REST, install one by your "
200 "own?"
201 << endl;
202 return -1;
203 }
204 int z = system(Form("mkdir -p %s/AddonDict", REST_USER_PATH.c_str()));
205 if (z != 0) {
206 cout << "mkdir failed to create directory" << endl;
207 return -1;
208 }
209
210 string linkdeffilename = REST_USER_PATH + (string) "/AddonDict/LinkDef.h";
211 ofstream ofs(linkdeffilename);
212 ofs << "#include <map>" << endl;
213 ofs << "#include <vector>" << endl;
214 ofs << "#include <map>" << endl;
215 ofs << "#include <set>" << endl;
216 ofs << "#include <list>" << endl;
217 ofs << "#include <array>" << endl;
218 ofs << "#ifdef __ROOTCLING__" << endl;
219 ofs << "#pragma link C++ class " << type << ";" << endl;
220 ofs << "#endif" << endl;
221 ofs.close();
222
223 string cxxfilename = REST_USER_PATH + (string) "/AddonDict/" + typeformatted + ".cxx";
224
225 cout << "Creating external dictionary for: \"" << type << "\":" << endl;
226 cout << sofilename << endl;
227
228 // cout << Form("rootcling -f %s -c %s", outfilename.c_str(), infilename.c_str()) << endl;
229 int a = system(Form("rootcling -f %s -c %s", cxxfilename.c_str(), linkdeffilename.c_str()));
230 if (a != 0) {
231 cout << "rootcling failed to generate dictionary" << endl;
232 return -1;
233 }
234
235 int b =
236 system(Form("gcc %s `root-config --cflags` "
237 "`root-config --libs` -lGui -lGeom -lGdml -lMinuit -L/usr/lib64 "
238 "-lstdc++ -shared -fPIC -o %s",
239 cxxfilename.c_str(), sofilename.c_str()));
240
241 // int c =
242 // system(Form("gcc %s/lib/AddonDict/*.cxx -std=c++11 -I`root-config --incdir` "
243 // "`root-config --libs` -lGui -lEve -lGeom -lMathMore -lGdml -lMinuit -L/usr/lib64 "
244 // "-lstdc++ -shared -fPIC -o %s/lib/AddonDict/libRestAddonDict.so",
245 // restpath, restpath));
246
247 if (b != 0 /*|| c != 0*/) {
248 cout << "gcc failed to generate library for the dictionary" << endl;
249 return -1;
250 }
251 }
252
253 gSystem->Load(sofilename.c_str());
254 RESTListOfClasses_typeid.clear();
255 RESTListOfClasses_typename.clear();
256 cl = GetClassQuick(type); // reset the TClass after loading external library.
257 typeinfo = cl->GetTypeInfo(); // update the typeinfo
258 return 0;
259}
260
262 return (type == "" || address == 0 || size == 0 || (cl == 0 && !is_data_type));
263}
264
265TRestReflector Assembly(string typeName) {
266 TRestReflector ptr = WrapType(typeName);
267 ptr.Assembly();
268 return ptr;
269}
270
271TRestReflector WrapType(string type) { return TRestReflector(0, type); }
272
274 if (from.IsZombie() || to.IsZombie()) {
275 cout << "In TRestReflector::CloneTo() : the ptr is zombie! " << endl;
276 return;
277 }
278
279 if (from.type != to.type) {
280 cout << "In TRestReflector::CloneTo() : type doesn't match! (This :" << from.type
281 << ", Target : " << to.type << ")" << endl;
282 return;
283 }
284
285 RESTVirtualConverter* converter = RESTConverterMethodBase[from.typeinfo->hash_code()];
286 if (converter != nullptr) {
287 converter->CloneObj(from.address, to.address);
288 } else {
289 cout << "Method for cloning type: \"" << from.type << "\" has not been registered!" << endl;
290 }
291 // if (from.cl == nullptr) {
292 // memcpy(to.address, from.address, from.size);
293 //} else {
294 // TBufferFile buffer(TBuffer::kWrite);
295
296 // buffer.MapObject(from.address, from.cl); // register obj in map to handle self reference
297 // from.cl->Streamer(from.address, buffer);
298
299 // buffer.SetReadMode();
300 // buffer.ResetMap();
301 // buffer.SetBufferOffset(0);
302
303 // buffer.MapObject(to.address, to.cl); // register obj in map to handle self reference
304 // to.cl->Streamer(to.address, buffer);
305 //}
306}
307
309 if (cl != nullptr) {
310 TDataMember* mem = cl->GetDataMember(name.c_str());
311 if (mem == nullptr) {
312 // find data member also in base class.
313 TVirtualStreamerInfo* vs = cl->GetStreamerInfo();
314 TObjArray* ses = vs->GetElements();
315 int n = ses->GetLast() + 1;
316 for (int i = 0; i < n; i++) {
317 TStreamerElement* ele = (TStreamerElement*)ses->At(i);
318 string type = ele->GetTypeName();
319 if (type == "BASE") {
320 char* addr = address + ele->GetOffset();
321 type = ele->GetClass()->GetName();
322 return TRestReflector(addr, type).GetDataMember(name);
323 }
324 }
325 } else {
326 char* addr = address + mem->GetOffset();
327 string type = mem->GetTypeName();
328 TRestReflector ptr(addr, type);
329 ptr.name = name;
330 return ptr;
331 }
332 }
333 return TRestReflector();
334}
335
337 if (cl != nullptr) {
338 TList* list = cl->GetListOfDataMembers();
339 if (ID < GetNumberOfDataMembers()) {
340 TDataMember* mem = (TDataMember*)list->At(ID);
341 char* addr = address + mem->GetOffset();
342 string type = mem->GetTypeName();
343 string name = mem->GetName();
344 TRestReflector ptr(addr, type);
345 ptr.name = name;
346 return ptr;
347 }
348 }
349 return TRestReflector();
350}
351
353 vector<string> dataMembers;
354
355 // add datamembers from base class first
356 TVirtualStreamerInfo* vs = cl->GetStreamerInfo();
357 TObjArray* ses = vs->GetElements();
358 int n = ses->GetLast() + 1;
359 for (int i = 0; i < n; i++) {
360 TStreamerElement* ele = (TStreamerElement*)ses->At(i);
361 string type = ele->GetTypeName();
362 if (type == "BASE") {
363 char* addr = address + ele->GetOffset();
364 type = ele->GetClass()->GetName();
365
366 auto baseDataMembers = TRestReflector(addr, type).GetListOfDataMembers();
367 dataMembers.insert(dataMembers.end(), baseDataMembers.begin(), baseDataMembers.end());
368 }
369 }
370
371 // then add datamembers of this class
372 TList* list = cl->GetListOfDataMembers();
373 for (int i = 0; i < list->GetSize(); i++) {
374 TDataMember* mem = (TDataMember*)list->At(i);
375 string name = mem->GetName();
376
377 dataMembers.push_back(name);
378 }
379
380 return dataMembers;
381}
382
385 if (!member.IsZombie()) {
386 return member.ToString();
387 }
388 return "";
389}
390
392 if (cl != nullptr) {
393 return cl->GetNdata();
394 }
395 return 0;
396}
397} // namespace REST_Reflection
void ParseString(std::string str)
Set the value of the wrapped object from std::string.
void Assembly()
Assembly a new object, and save its address. The old object will be destroied if not null.
std::string ToString()
Convert the wrapped object to std::string.
TRestReflector()
Default constructor.
std::string GetDataMemberValueString(std::string name)
Get the value of datamember as std::string.
std::string type
Type of the wrapped object.
int size
Size of the object.
std::vector< std::string > GetListOfDataMembers()
Get a list of the class's datamembers as a std::vector of std::string, including those from base clas...
char * address
Address of the wrapped object.
TClass * cl
Pointer to the corresponding TClass helper, if the wrapped object is in class type.
bool is_data_type
Pointer to the corresponding TDataType helper, if the wrapped object is in data type.
void operator>>(TRestReflector to)
Deep copy the content of the wrapped object to to.
int GetNumberOfDataMembers()
Get the number of data members of a class.
TRestReflector GetDataMember(std::string name)
Find the class's datamember as TRestReflector object, including those from base class.
std::string name
Name field.
void PrintMemory(int bytepreline=16)
Print the Hex memory std::map of the wrappered object.
void Destroy()
Destroy the current object. It will make the class to be zombie.
const std::type_info * typeinfo
value of typeid(T).name() of the wrapped object
bool IsZombie()
If this object type wrapper is invalid.
bool onheap
If on heap, we can call Destroy() to TRestReflector. True only when initialized from Assembly()
int InitDictionary()
Prepare the ROOT dictionary for this type.
static bool fileExists(const std::string &filename)
Returns true if the file (or directory) with path filename exists.
Definition: TRestTools.cxx:674
static bool isPathWritable(const std::string &path)
Returns true if the path given by argument is writable.
Definition: TRestTools.cxx:724
This namespace serves for the reflection functionality.
TRestReflector WrapType(std::string typeName)
Wrap information an object of type: typeName, memory is not allocated.
TClass * GetClassQuick(std::string type)
void CloneAny(TRestReflector from, TRestReflector to)
Deep copy the content of object from to to
TRestReflector Assembly(std::string typeName)
Assembly an object of type: typeName, returning the allocated memory address and size.
std::string RemoveWhiteSpaces(std::string in)
Returns the input string removing all white spaces.
std::string Replace(std::string in, std::string thisString, std::string byThisString, size_t fromPosition=0, Int_t N=0)
Replace every occurences of thisSring by byThisString inside string in.