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