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 
9 using namespace std;
10 
11 namespace REST_Reflection {
57 TRestReflector::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 
72  InitDictionary();
73 }
74 
75 void TRestReflector::Assembly() {
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 
90 void TRestReflector::Destroy() const {
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 
107 void 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 
124 void TRestReflector::operator>>(const TRestReflector& to) { CloneAny(*this, to); }
125 
126 string TRestReflector::ToString() const {
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 
141 void 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 
154 int TRestReflector::InitDictionary() {
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 
256 bool TRestReflector::IsZombie() const {
257  return (type.empty() || address == nullptr || size == 0 || (cl == nullptr && !is_data_type));
258 }
259 
260 TRestReflector Assembly(const string& typeName) {
261  TRestReflector ptr = WrapType(typeName);
262  ptr.Assembly();
263  return ptr;
264 }
265 
266 TRestReflector WrapType(const string& type) { return TRestReflector(nullptr, type); }
267 
268 void 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 
288 TRestReflector TRestReflector::GetDataMember(const string& name) {
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 
316 TRestReflector TRestReflector::GetDataMember(int ID) {
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 
332 vector<string> TRestReflector::GetListOfDataMembers() const {
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 
363 string TRestReflector::GetDataMemberValueString(const string& name) {
364  TRestReflector member = GetDataMember(name);
365  if (!member.IsZombie()) {
366  return member.ToString();
367  }
368  return "";
369 }
370 
371 int TRestReflector::GetNumberOfDataMembers() const {
372  if (cl != nullptr) {
373  return cl->GetNdata();
374  }
375  return 0;
376 }
377 } // namespace REST_Reflection
void Assembly()
Assembly a new object, and save its address. The old object will be destroied if not null.
std::string type
Type of the wrapped object.
char * address
Address of the wrapped object.
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.
const std::type_info * typeinfo
value of typeid(T).name() of the wrapped object
TRestReflector GetDataMember(const std::string &name)
Find the class's datamember as TRestReflector object, including those from base class.
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.