ROOT  6.07/01
Reference Guide
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
TClassEdit.cxx
Go to the documentation of this file.
1 // @(#)root/metautils:$Id$
2 // Author: Victor Perev 04/10/2003
3 // Philippe Canal 05/2004
4 
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <assert.h>
8 #include <string.h>
9 #include "TClassEdit.h"
10 #include <ctype.h>
11 #include "Rstrstream.h"
12 #include <set>
13 // for shared_ptr
14 #include <memory>
15 #include "RStringView.h"
16 
17 namespace {
18  static TClassEdit::TInterpreterLookupHelper *gInterpreterHelper = 0;
19 }
20 
21 namespace std {} using namespace std;
22 
23 ////////////////////////////////////////////////////////////////////////////////
24 /// Return the length, if any, taken by std:: and any
25 /// potential inline namespace (well compiler detail namespace).
26 
27 static size_t StdLen(const std::string_view name)
28 {
29  size_t len = 0;
30  if (name.compare(0,5,"std::")==0) {
31  len = 5;
32 
33  // TODO: This is likely to induce unwanted autoparsing, those are reduced
34  // by the caching of the result.
35  if (gInterpreterHelper) {
36  for(size_t i = 5; i < name.length(); ++i) {
37  if (name[i] == '<') break;
38  if (name[i] == ':') {
39  bool isInlined;
40  std::string scope(name.data(),i);
41  std::string scoperesult;
42  // We assume that we are called in already serialized code.
43  // Note: should we also cache the negative answers?
44  static std::set<std::string> gInlined;
45 
46  if (gInlined.find(scope) != gInlined.end()) {
47  len = i;
48  if (i+1<name.length() && name[i+1]==':') {
49  len += 2;
50  }
51  }
52  if (!gInterpreterHelper->ExistingTypeCheck(scope, scoperesult)
53  && gInterpreterHelper->IsDeclaredScope(scope,isInlined)) {
54  if (isInlined) {
55  gInlined.insert(scope);
56  len = i;
57  if (i+1<name.length() && name[i+1]==':') {
58  len += 2;
59  }
60  }
61  }
62  }
63  }
64  }
65  }
66 
67  return len;
68 }
69 
70 ////////////////////////////////////////////////////////////////////////////////
71 /// Remove std:: and any potential inline namespace (well compiler detail
72 /// namespace.
73 
74 static void RemoveStd(std::string &name, size_t pos = 0)
75 {
76  size_t len = StdLen({name.data()+pos,name.length()-pos});
77  if (len) {
78  name.erase(pos,len);
79  }
80 }
81 
82 ////////////////////////////////////////////////////////////////////////////////
83 /// Remove std:: and any potential inline namespace (well compiler detail
84 /// namespace.
85 
86 static void RemoveStd(std::string_view &name)
87 {
88  size_t len = StdLen(name);
89  if (len) {
90  name.remove_prefix(len);
91  }
92 }
93 
94 ////////////////////////////////////////////////////////////////////////////////
95 
97 {
98  if (0 == strncmp(clName, "complex<", 8)) {
99  const char *clNamePlus8 = clName + 8;
100  if (0 == strcmp("float>", clNamePlus8)) {
101  return EComplexType::kFloat;
102  }
103  if (0 == strcmp("double>", clNamePlus8)) {
104  return EComplexType::kDouble;
105  }
106  if (0 == strcmp("int>", clNamePlus8)) {
107  return EComplexType::kInt;
108  }
109  if (0 == strcmp("long>", clNamePlus8)) {
110  return EComplexType::kLong;
111  }
112  }
113  return EComplexType::kNone;
114 }
115 
116 ////////////////////////////////////////////////////////////////////////////////
117 
119 {
120  gInterpreterHelper = helper;
121 }
122 
123 ////////////////////////////////////////////////////////////////////////////////
124 /// default constructor
125 
126 TClassEdit::TSplitType::TSplitType(const char *type2split, EModType mode) : fName(type2split), fNestedLocation(0)
127 {
128  TClassEdit::GetSplit(type2split, fElements, fNestedLocation, mode);
129 }
130 
131 ////////////////////////////////////////////////////////////////////////////////
132 /// type : type name: vector<list<classA,allocator>,allocator>[::iterator]
133 /// result: 0 : not stl container and not declared inside an stl container.
134 /// result: code of container that the type or is the scope of the type
135 
137 {
138  if (fElements[0].empty()) return ROOT::kNotSTL;
139  return STLKind(fElements[0]);
140 }
141 
142 ////////////////////////////////////////////////////////////////////////////////
143 /// type : type name: vector<list<classA,allocator>,allocator>
144 /// testAlloc: if true, we test allocator, if it is not default result is negative
145 /// result: 0 : not stl container
146 /// abs(result): code of container 1=vector,2=list,3=deque,4=map
147 /// 5=multimap,6=set,7=multiset
148 /// positive val: we have a vector or list with default allocator to any depth
149 /// like vector<list<vector<int>>>
150 /// negative val: STL container other than vector or list, or non default allocator
151 /// For example: vector<deque<int>> has answer -1
152 
153 int TClassEdit::TSplitType::IsSTLCont(int testAlloc) const
154 {
155 
156  if (fElements[0].empty()) return 0;
157  int numb = fElements.size();
158  if (!fElements[numb-1].empty() && fElements[numb-1][0]=='*') --numb;
159 
160  if ( fNestedLocation ) {
161  // The type has been defined inside another namespace and/or class
162  // this couldn't possibly be an STL container
163  return 0;
164  }
165 
166  int kind = STLKind(fElements[0]);
167 
168  if (kind==ROOT::kSTLvector || kind==ROOT::kSTLlist || kind==ROOT::kSTLforwardlist) {
169 
170  int nargs = STLArgs(kind);
171  if (testAlloc && (numb-1 > nargs) && !IsDefAlloc(fElements[numb-1].c_str(),fElements[1].c_str())) {
172 
173  // We have a non default allocator,
174  // let's return a negative value.
175 
176  kind = -kind;
177 
178  } else {
179 
180  // We has a default allocator, let's continue to
181  // look inside the argument list.
182  int k = TClassEdit::IsSTLCont(fElements[1].c_str(),testAlloc);
183  if (k<0) kind = -kind;
184 
185  }
186  }
187 
188  // We return a negative value for anything which is not a vector or a list.
189  if(kind>2) kind = - kind;
190  return kind;
191 }
192 #include <iostream>
193 ////////////////////////////////////////////////////////////////////////////////
194 //////////////////////////////////////////////////////////////////////////////
195 /// Return the absolute type of typeDesc into the string answ.
196 
197 void TClassEdit::TSplitType::ShortType(std::string &answ, int mode)
198 {
199  // E.g.: typeDesc = "class const volatile TNamed**", returns "TNamed**".
200  // if (mode&1) remove last "*"s returns "TNamed"
201  // if (mode&2) remove default allocators from STL containers
202  // if (mode&4) remove all allocators from STL containers
203  // if (mode&8) return inner class of stl container. list<innerClass>
204  // if (mode&16) return deepest class of stl container. vector<list<deepest>>
205  // if (mode&kDropAllDefault) remove default template arguments
206  /////////////////////////////////////////////////////////////////////////////
207 
208  answ.clear();
209  int narg = fElements.size();
210  int tailLoc = 0;
211 
212  if (narg == 0) {
213  answ = fName;
214  return ;
215  }
216  // fprintf(stderr,"calling ShortType %d for %s with narg %d\n",mode,typeDesc,narg);
217  // {for (int i=0;i<narg;i++) fprintf(stderr,"calling ShortType %d for %s with %d %s \n",
218  // mode,typeDesc,i,arglist[i].c_str());
219  // }
220  if (fElements[narg-1].empty() == false &&
221  (fElements[narg-1][0]=='*'
222  || fElements[narg-1][0]=='&'
223  || fElements[narg-1][0]=='['
224  || 0 == fElements[narg-1].compare(0,6,"const*")
225  || 0 == fElements[narg-1].compare(0,6,"const&")
226  || 0 == fElements[narg-1].compare(0,6,"const[")
227  || 0 == fElements[narg-1].compare("const")
228  )
229  ) {
230  if ((mode&1)==0) tailLoc = narg-1;
231  }
232  else { assert(fElements[narg-1].empty()); };
233  narg--;
234  mode &= (~1);
235 
236  if (fNestedLocation) narg--;
237 
238  // fprintf(stderr,"calling ShortType %d for %s with narg %d tail %d\n",imode,typeDesc,narg,tailLoc);
239 
240  //kind of stl container
241  const int kind = STLKind(fElements[0]);
242  const int iall = STLArgs(kind);
243 
244  // Only class is needed
245  if (mode&(8|16)) {
246  while(narg-1>iall) { fElements.pop_back(); narg--;}
247  if (!fElements[0].empty() && tailLoc) {
248  tailLoc = 0;
249  }
250  fElements[0].clear();
251  mode&=(~8);
252  }
253 
254  if (mode & kDropAllDefault) mode |= kDropStlDefault;
255  if (mode & kDropStlDefault) mode |= kDropDefaultAlloc;
256 
257  if (kind) {
258  bool allocRemoved = false;
259 
260  if ( mode & (kDropDefaultAlloc|kDropAlloc) ) {
261  // remove allocators
262 
263 
264  if (narg-1 == iall+1) {
265  // has an allocator specified
266  bool dropAlloc = false;
267  if (mode & kDropAlloc) {
268 
269  dropAlloc = true;
270 
271  } else if (mode & kDropDefaultAlloc) {
272  switch (kind) {
273  case ROOT::kSTLvector:
274  case ROOT::kSTLlist:
276  case ROOT::kSTLdeque:
277  case ROOT::kSTLset:
278  case ROOT::kSTLmultiset:
281  dropAlloc = IsDefAlloc(fElements[iall+1].c_str(),fElements[1].c_str());
282  break;
283  case ROOT::kSTLmap:
284  case ROOT::kSTLmultimap:
287  dropAlloc = IsDefAlloc(fElements[iall+1].c_str(),fElements[1].c_str(),fElements[2].c_str());
288  break;
289  default:
290  dropAlloc = false;
291  }
292 
293  }
294  if (dropAlloc) {
295  narg--;
296  allocRemoved = true;
297  }
298  } else {
299  // has no allocator specified (hence it is already removed!)
300  allocRemoved = true;
301  }
302  }
303 
304  if ( allocRemoved && (mode & kDropStlDefault) && narg-1 == iall) { // remove default comparator
305  if ( IsDefComp( fElements[iall].c_str(), fElements[1].c_str() ) ) {
306  narg--;
307  }
308  } else if ( mode & kDropComparator ) {
309 
310  switch (kind) {
311  case ROOT::kSTLvector:
312  case ROOT::kSTLlist:
314  case ROOT::kSTLdeque:
315  break;
316  case ROOT::kSTLset:
317  case ROOT::kSTLmultiset:
318  case ROOT::kSTLmap:
319  case ROOT::kSTLmultimap:
320  if (!allocRemoved && narg-1 == iall+1) {
321  narg--;
322  allocRemoved = true;
323  }
324  if (narg-1 == iall) narg--;
325  break;
326  default:
327  break;
328  }
329  }
330 
331  // Treat now Pred and Hash for unordered set/map containers. Signature is:
332  // template < class Key,
333  // class Hash = hash<Key>,
334  // class Pred = equal_to<Key>,
335  // class Alloc = allocator<Key>
336  // > class unordered_{set,multiset}
337  // template < class Key,
338  // class Val,
339  // class Hash = hash<Key>,
340  // class Pred = equal_to<Key>,
341  // class Alloc = allocator<Key>
342  // > class unordered_{map,multimap}
343 
344 
346 
347  bool predRemoved = false;
348 
349  if ( allocRemoved && (mode & kDropStlDefault) && narg-1 == iall) { // remove default predicate
350  if ( IsDefPred( fElements[iall].c_str(), fElements[1].c_str() ) ) {
351  predRemoved=true;
352  narg--;
353  }
354  }
355 
356  if ( predRemoved && (mode & kDropStlDefault) && narg == iall) { // remove default hash
357  if ( IsDefHash( fElements[iall-1].c_str(), fElements[1].c_str() ) ) {
358  narg--;
359  }
360  }
361  }
362  } // End of treatment of stl containers
363  else {
364  if ( (mode & kDropStlDefault) && (narg >= 3)) {
365  unsigned int offset = (0==strncmp("const ",fElements[0].c_str(),6)) ? 6 : 0;
366  offset += (0==strncmp("std::",fElements[0].c_str()+offset,5)) ? 5 : 0;
367  if (0 == strcmp(fElements[0].c_str()+offset,"__shared_ptr"))
368  {
369 #ifdef _CONCURRENCE_H
370  static const std::string sharedPtrDef = std::to_string(__gnu_cxx::__default_lock_policy); // to_string is C++11
371 #else
372  static const std::string sharedPtrDef = std::to_string(2); // to_string is C++11
373 #endif
374  if (fElements[2] == sharedPtrDef) {
375  narg--;
376  }
377  }
378  }
379  }
380 
381  // do the same for all inside
382  for (int i=1;i<narg; i++) {
383  if (strchr(fElements[i].c_str(),'<')==0) {
384  if (mode&kDropStd) {
385  unsigned int offset = (0==strncmp("const ",fElements[i].c_str(),6)) ? 6 : 0;
386  RemoveStd( fElements[i], offset );
387  }
388  if (mode&kResolveTypedef) {
389  fElements[i] = ResolveTypedef(fElements[i].c_str(),true);
390  }
391  continue;
392  }
393  fElements[i] = TClassEdit::ShortType(fElements[i].c_str(),mode | TClassEdit::kKeepOuterConst);
394  if (mode&kResolveTypedef) {
395  // We 'just' need to check whether the outer type is a typedef or not;
396  // this also will add the default template parameter if any needs to
397  // be added.
398  string typeresult;
399  if (gInterpreterHelper->ExistingTypeCheck(fElements[i], typeresult)
400  || gInterpreterHelper->GetPartiallyDesugaredNameWithScopeHandling(fElements[i], typeresult)) {
401  if (!typeresult.empty()) fElements[i] = typeresult;
402  }
403  }
404  }
405 
406  unsigned int tailOffset = 0;
407  if (tailLoc && fElements[tailLoc].compare(0,5,"const") == 0) {
408  if (mode & kKeepOuterConst) answ += "const ";
409  tailOffset = 5;
410  }
411  if (!fElements[0].empty()) {answ += fElements[0]; answ +="<";}
412 
413 #if 0
414  // This code is no longer use, the moral equivalent would be to get
415  // the 'fixed' number of argument the user told us to ignore and drop those.
416  // However, the name we get here might be (usually) normalized enough that
417  // this is not necessary (at the very least nothing break in roottest without
418  // the aforementioned new code or this old code).
419  if (mode & kDropAllDefault) {
420  int nargNonDefault = 0;
421  std::string nonDefName = answ;
422  // "superlong" because tLong might turn fName into an even longer name
423  std::string nameSuperLong = fName;
424  if (gInterpreterHelper)
425  gInterpreterHelper->GetPartiallyDesugaredName(nameSuperLong);
426  while (++nargNonDefault < narg) {
427  // If T<a> is a "typedef" (aka default template params)
428  // to T<a,b> then we can strip the "b".
429  const char* closeTemplate = " >";
430  if (nonDefName[nonDefName.length() - 1] != '>')
431  ++closeTemplate;
432  string nondef = nonDefName + closeTemplate;
433  if (gInterpreterHelper &&
434  gInterpreterHelper->IsAlreadyPartiallyDesugaredName(nondef, nameSuperLong))
435  break;
436  if (nargNonDefault>1) nonDefName += ",";
437  nonDefName += fElements[nargNonDefault];
438  }
439  if (nargNonDefault < narg)
440  narg = nargNonDefault;
441  }
442 #endif
443 
444  { for (int i=1;i<narg-1; i++) { answ += fElements[i]; answ+=",";} }
445  if (narg>1) { answ += fElements[narg-1]; }
446 
447  if (!fElements[0].empty()) {
448  if ( answ.at(answ.size()-1) == '>') {
449  answ += " >";
450  } else {
451  answ += '>';
452  }
453  }
454  if (fNestedLocation) {
455  // Treat X pf A<B>::X
456  fElements[fNestedLocation] = TClassEdit::ShortType(fElements[fNestedLocation].c_str(),mode);
457  answ += fElements[fNestedLocation];
458  }
459  // tail is not a type name, just [2], &, * etc.
460  if (tailLoc) answ += fElements[tailLoc].c_str()+tailOffset;
461 }
462 
463 ////////////////////////////////////////////////////////////////////////////////
464 /// Converts STL container name to number. vector -> 1, etc..
465 /// If len is greater than 0, only look at that many characters in the string.
466 
468 {
469  unsigned char offset = 0;
470  if (type.compare(0,6,"const ")==0) { offset += 6; }
471  offset += StdLen(type.substr(offset));
472 
473  //container names
474  static const char *stls[] =
475  { "any", "vector", "list", "deque", "map", "multimap", "set", "multiset", "bitset",
476  "forward_list", "unordered_set", "unordered_multiset", "unordered_map", "unordered_multimap", 0};
477  static const size_t stllen[] =
478  { 3, 6, 4, 5, 3, 8, 3, 8, 6,
479  12, 13, 18, 13, 18, 0};
480  static const ROOT::ESTLType values[] =
486  // New C++11
491  };
492 
493  // kind of stl container
494  auto len = type.length();
495  if (len) {
496  len -= offset;
497  for(int k=1;stls[k];k++) {
498  if (len == stllen[k]) {
499  if (type.compare(offset,len,stls[k])==0) return values[k];
500  }
501  }
502  } else {
503  for(int k=1;stls[k];k++) {if (type.compare(offset,len,stls[k])==0) return values[k];}
504  }
505  return ROOT::kNotSTL;
506 }
507 
508 ////////////////////////////////////////////////////////////////////////////////
509 /// Return number of arguments for STL container before allocator
510 
511 int TClassEdit::STLArgs(int kind)
512 {
513  static const char stln[] =// min number of container arguments
514  // vector, list, deque, map, multimap, set, multiset, bitset,
515  { 1, 1, 1, 1, 3, 3, 2, 2, 1,
516  // forward_list, unordered_set, unordered_multiset, unordered_map, unordered_multimap
517  1, 3, 3, 4, 4};
518 
519  return stln[kind];
520 }
521 
522 ////////////////////////////////////////////////////////////////////////////////
523 
524 static size_t findNameEnd(const std::string_view full)
525 {
526  int level = 0;
527  for(size_t i = 0; i < full.length(); ++i) {
528  switch(full[i]) {
529  case '<': { ++level; break; }
530  case '>': {
531  if (level == 0) return i;
532  else --level;
533  break;
534  }
535  case ',': {
536  if (level == 0) return i;
537  break;
538  }
539  default: break;
540  }
541  }
542  return full.length();
543 }
544 
545 ////////////////////////////////////////////////////////////////////////////////
546 
547 static size_t findNameEnd(const std::string &full, size_t pos)
548 {
549  return pos + findNameEnd( {full.data()+pos,full.length()-pos} );
550 }
551 
552 ////////////////////////////////////////////////////////////////////////////////
553 /// return whether or not 'allocname' is the STL default allocator for type
554 /// 'classname'
555 
556 bool TClassEdit::IsDefAlloc(const char *allocname, const char *classname)
557 {
558  string_view a( allocname );
559  RemoveStd(a);
560 
561  if (a=="alloc") return true;
562  if (a=="__default_alloc_template<true,0>") return true;
563  if (a=="__malloc_alloc_template<0>") return true;
564 
565  const static int alloclen = strlen("allocator<");
566  if (a.compare(0,alloclen,"allocator<") != 0) {
567  return false;
568  }
569  a.remove_prefix(alloclen);
570 
571  RemoveStd(a);
572 
573  string_view k = classname;
574  RemoveStd(k);
575 
576  if (a.compare(0,k.length(),k) != 0) {
577  // Now we need to compare the normalized name.
578  size_t end = findNameEnd(a);
579 
580  std::string valuepart;
581  GetNormalizedName(valuepart,std::string_view(a.data(),end));
582 
583  std::string norm_value;
584  GetNormalizedName(norm_value,k);
585 
586  if (valuepart != norm_value) {
587  return false;
588  }
589  a.remove_prefix(end);
590  } else {
591  a.remove_prefix(k.length());
592  }
593 
594  if (a.compare(0,1,">")!=0 && a.compare(0,2," >")!=0) {
595  return false;
596  }
597 
598  return true;
599 }
600 
601 ////////////////////////////////////////////////////////////////////////////////
602 /// return whether or not 'allocname' is the STL default allocator for a key
603 /// of type 'keyclassname' and a value of type 'valueclassname'
604 
605 bool TClassEdit::IsDefAlloc(const char *allocname,
606  const char *keyclassname,
607  const char *valueclassname)
608 {
609  if (IsDefAlloc(allocname,keyclassname)) return true;
610 
611  string_view a( allocname );
612  RemoveStd(a);
613 
614  const static int alloclen = strlen("allocator<");
615  if (a.compare(0,alloclen,"allocator<") != 0) {
616  return false;
617  }
618  a.remove_prefix(alloclen);
619 
620  RemoveStd(a);
621 
622  const static int pairlen = strlen("pair<");
623  if (a.compare(0,pairlen,"pair<") != 0) {
624  return false;
625  }
626  a.remove_prefix(pairlen);
627 
628  const static int constlen = strlen("const ");
629  if (a.compare(0,constlen,"const ") == 0) {
630  a.remove_prefix(constlen);
631  }
632 
633  RemoveStd(a);
634 
635  string_view k = keyclassname;
636  RemoveStd(k);
637 
638  if (a.compare(0,k.length(),k) != 0) {
639  // Now we need to compare the normalized name.
640  size_t end = findNameEnd(a);
641 
642  std::string keypart;
643  GetNormalizedName(keypart,std::string_view(a.data(),end));
644 
645  std::string norm_key;
646  GetNormalizedName(norm_key,k);
647 
648  if (keypart != norm_key) {
649  if ( k[k.length()-1] == '*' ) {
650  // also check with a trailing 'const'.
651  keypart += "const";
652  if (keypart != norm_key) {
653  return false;
654  }
655  } else {
656  return false;
657  }
658  }
659  a.remove_prefix(end);
660  } else {
661  a.remove_prefix(k.length());
662  }
663 
664  if (a[0] != ',') {
665  return false;
666  }
667  a.remove_prefix(1);
668  RemoveStd(a);
669 
670  string_view v = valueclassname;
671  RemoveStd(v);
672 
673  if (a.compare(0,v.length(),v) != 0) {
674  // Now we need to compare the normalized name.
675  size_t end = findNameEnd(a);
676 
677  std::string valuepart;
678  GetNormalizedName(valuepart,std::string_view(a.data(),end));
679 
680  std::string norm_value;
681  GetNormalizedName(norm_value,v);
682 
683  if (valuepart != norm_value) {
684  return false;
685  }
686  a.remove_prefix(end);
687  } else {
688  a.remove_prefix(v.length());
689  }
690 
691  if (a.compare(0,1,">")!=0 && a.compare(0,2," >")!=0) {
692  return false;
693  }
694 
695  return true;
696 }
697 
698 ////////////////////////////////////////////////////////////////////////////////
699 /// return whether or not 'elementName' is the STL default Element for type
700 /// 'classname'
701 
702 static bool IsDefElement(const char *elementName, const char* defaultElementName, const char *classname)
703 {
704  string c = elementName;
705 
706  size_t pos = StdLen(c);
707 
708  const int elementlen = strlen(defaultElementName);
709  if (c.compare(pos,elementlen,defaultElementName) != 0) {
710  return false;
711  }
712  pos += elementlen;
713 
714  string k = classname;
715  if (c.compare(pos,k.length(),k) != 0) {
716  // Now we need to compare the normalized name.
717  size_t end = findNameEnd(c,pos);
718 
719  std::string keypart;
720  TClassEdit::GetNormalizedName(keypart,std::string_view(c.c_str()+pos,end-pos));
721 
722  std::string norm_key;
723  TClassEdit::GetNormalizedName(norm_key,k.c_str());
724 
725  if (keypart != norm_key) {
726  return false;
727  }
728  pos = end;
729  } else {
730  pos += k.length();
731  }
732 
733  if (c.compare(pos,1,">")!=0 && c.compare(pos,2," >")!=0) {
734  return false;
735  }
736 
737  return true;
738 }
739 
740 ////////////////////////////////////////////////////////////////////////////////
741 /// return whether or not 'compare' is the STL default comparator for type
742 /// 'classname'
743 
744 bool TClassEdit::IsDefComp(const char *compname, const char *classname)
745 {
746  return IsDefElement(compname, "less<", classname);
747 }
748 
749 ////////////////////////////////////////////////////////////////////////////////
750 /// return whether or not 'predname' is the STL default predicate for type
751 /// 'classname'
752 
753 bool TClassEdit::IsDefPred(const char *predname, const char *classname)
754 {
755  return IsDefElement(predname, "equal_to<", classname);
756 }
757 
758 ////////////////////////////////////////////////////////////////////////////////
759 /// return whether or not 'hashname' is the STL default hash for type
760 /// 'classname'
761 
762 bool TClassEdit::IsDefHash(const char *hashname, const char *classname)
763 {
764  return IsDefElement(hashname, "hash<", classname);
765 }
766 
767 ////////////////////////////////////////////////////////////////////////////////
768 /// Return the normalized name. See TMetaUtils::GetNormalizedName.
769 ///
770 /// Return the type name normalized for ROOT,
771 /// keeping only the ROOT opaque typedef (Double32_t, etc.) and
772 /// removing the STL collections default parameter if any.
773 ///
774 /// Compare to TMetaUtils::GetNormalizedName, this routines does not
775 /// and can not add default template parameters.
776 
777 void TClassEdit::GetNormalizedName(std::string &norm_name, std::string_view name)
778 {
779  norm_name = std::string(name); // NOTE: Is that the shortest version?
780 
781  // Remove the std:: and default template argument and insert the Long64_t and change basic_string to string.
784 
785  // Depending on how the user typed their code, in particular typedef
786  // declarations, we may end up with an explicit '::' being
787  // part of the result string. For consistency, we must remove it.
788  if (norm_name.length()>2 && norm_name[0]==':' && norm_name[1]==':') {
789  norm_name.erase(0,2);
790  }
791 
792  if (gInterpreterHelper) {
793  // See if the expanded name itself is a typedef.
794  std::string typeresult;
795  if (gInterpreterHelper->ExistingTypeCheck(norm_name, typeresult)
796  || gInterpreterHelper->GetPartiallyDesugaredNameWithScopeHandling(norm_name, typeresult)) {
797 
798  if (!typeresult.empty()) norm_name = typeresult;
799  }
800  }
801 }
802 
803 ////////////////////////////////////////////////////////////////////////////////
804 /// Replace 'long long' and 'unsigned long long' by 'Long64_t' and 'ULong64_t'
805 
806 string TClassEdit::GetLong64_Name(const char* original)
807 {
808  if (original==0)
809  return "";
810  else
811  return GetLong64_Name(string(original));
812 }
813 
814 ////////////////////////////////////////////////////////////////////////////////
815 /// Replace 'long long' and 'unsigned long long' by 'Long64_t' and 'ULong64_t'
816 
817 string TClassEdit::GetLong64_Name(const string& original)
818 {
819  static const char* longlong_s = "long long";
820  static const char* ulonglong_s = "unsigned long long";
821  static const unsigned int longlong_len = strlen(longlong_s);
822  static const unsigned int ulonglong_len = strlen(ulonglong_s);
823 
824  string result = original;
825 
826  int pos = 0;
827  while( (pos = result.find(ulonglong_s,pos) ) >=0 ) {
828  result.replace(pos, ulonglong_len, "ULong64_t");
829  }
830  pos = 0;
831  while( (pos = result.find(longlong_s,pos) ) >=0 ) {
832  result.replace(pos, longlong_len, "Long64_t");
833  }
834  return result;
835 }
836 
837 ////////////////////////////////////////////////////////////////////////////////
838 /// Return the start of the unqualified name include in 'original'.
839 
840 const char *TClassEdit::GetUnqualifiedName(const char *original)
841 {
842  const char *lastPos = original;
843  {
844  long depth = 0;
845  for(auto cursor = original; *cursor != '\0'; ++cursor) {
846  if ( *cursor == '<' || *cursor == '(') ++depth;
847  else if ( *cursor == '>' || *cursor == ')' ) --depth;
848  else if ( *cursor == ':' ) {
849  if (depth==0 && *(cursor+1) == ':' && *(cursor+2) != '\0') {
850  lastPos = cursor+2;
851  }
852  }
853  }
854  }
855  return lastPos;
856 }
857 
858 ////////////////////////////////////////////////////////////////////////////////
859 
860 static void R__FindTrailing(std::string &full, /*modified*/
861  std::string &stars /* the literal output */
862  )
863 {
864  const char *t = full.c_str();
865  const unsigned int tlen( full.size() );
866 
867  const char *starloc = t + tlen - 1;
868  bool hasconst = false;
869  if ( (*starloc)=='t'
870  && (starloc-t) > 4 && 0 == strncmp((starloc-4),"const",5)
871  && ( (*(starloc-5)) == ' ' || (*(starloc-5)) == '*' || (*(starloc-5)) == '&'
872  || (*(starloc-5)) == '>' || (*(starloc-5)) == ']') ) {
873  // we are ending on a const.
874  starloc -= 4;
875  if ((*starloc-1)==' ') {
876  // Take the space too.
877  starloc--;
878  }
879  hasconst = true;
880  }
881  if ( hasconst || (*starloc)=='*' || (*starloc)=='&' || (*starloc)==']' ) {
882  bool isArray = ( (*starloc)==']' );
883  while( t<=(starloc-1) && ((*(starloc-1))=='*' || (*(starloc-1))=='&' || (*(starloc-1))=='t' || isArray)) {
884  if (isArray) {
885  starloc--;
886  isArray = ! ( (*starloc)=='[' );
887  } else if ( (*(starloc-1))=='t' ) {
888  if ( (starloc-1-t) > 5 && 0 == strncmp((starloc-5),"const",5)
889  && ( (*(starloc-6)) == ' ' || (*(starloc-6)) == '*' || (*(starloc-6)) == '&'
890  || (*(starloc-6)) == '>' || (*(starloc-6)) == ']')) {
891  // we have a const.
892  starloc -= 5;
893  } else {
894  break;
895  }
896  } else {
897  starloc--;
898  }
899  }
900  stars = starloc;
901  if ((*(starloc-1))==' ') {
902  // erase the space too.
903  starloc--;
904  }
905 
906  const unsigned int starlen = strlen(starloc);
907  full.erase(tlen-starlen,starlen);
908  } else if (hasconst) {
909  stars = starloc;
910  const unsigned int starlen = strlen(starloc);
911  full.erase(tlen-starlen,starlen);
912  }
913 
914 }
915 
916 ////////////////////////////////////////////////////////////////////////////////
917 ////////////////////////////////////////////////////////////////////////////
918 /// Stores in output (after emptying it) the splited type.
919 /// Stores the location of the tail (nested names) in nestedLoc (0 indicates no tail).
920 /// Return the number of elements stored.
921 ///
922 /// First in list is the template name or is empty
923 /// "vector<list<int>,alloc>**" to "vector" "list<int>" "alloc" "**"
924 /// or "TNamed*" to "" "TNamed" "*"
925 ////////////////////////////////////////////////////////////////////////////
926 
927 int TClassEdit::GetSplit(const char *type, vector<string>& output, int &nestedLoc, EModType mode)
928 {
929  nestedLoc = 0;
930  output.clear();
931  if (strlen(type)==0) return 0;
932 
933  int cleantypeMode = 1 /* keepInnerConst */;
934  if (mode & kKeepOuterConst) {
935  cleantypeMode = 0; /* remove only the outer class keyword */
936  }
937  string full( mode & kLong64 ? TClassEdit::GetLong64_Name( CleanType(type, cleantypeMode) )
938  : CleanType(type, cleantypeMode) );
939 
940  // We need to replace basic_string with string.
941  {
942  unsigned int const_offset = (0==strncmp("const ",full.c_str(),6)) ? 6 : 0;
943  bool isString = false;
944  bool isStdString = false;
945  static const char* basic_string_std = "std::basic_string<char";
946  static const unsigned int basic_string_std_len = strlen(basic_string_std);
947 
948  if (full.compare(const_offset,basic_string_std_len,basic_string_std) == 0
949  && full.size() > basic_string_std_len) {
950  isString = true;
951  isStdString = true;
952  } else if (full.compare(const_offset,basic_string_std_len-5,basic_string_std+5) == 0
953  && full.size() > (basic_string_std_len-5)) {
954  // no std.
955  isString = true;
956  }
957  if (isString) {
958  size_t offset = isStdString ? basic_string_std_len : basic_string_std_len - 5;
959  offset += const_offset;
960  if ( full[offset] == '>' ) {
961  // done.
962  } else if (full[offset] == ',') {
963  ++offset;
964  if (full.compare(offset, 5, "std::") == 0) {
965  offset += 5;
966  }
967  static const char* char_traits_s = "char_traits<char>";
968  static const unsigned int char_traits_len = strlen(char_traits_s);
969  if (full.compare(offset, char_traits_len, char_traits_s) == 0) {
970  offset += char_traits_len;
971  if ( full[offset] == '>') {
972  // done.
973  } else if (full[offset] == ' ' && full[offset+1] == '>') {
974  ++offset;
975  // done.
976  } else if (full[offset] == ',') {
977  ++offset;
978  if (full.compare(offset, 5, "std::") == 0) {
979  offset += 5;
980  }
981  static const char* allocator_s = "allocator<char>";
982  static const unsigned int allocator_len = strlen(allocator_s);
983  if (full.compare(offset, allocator_len, allocator_s) == 0) {
984  offset += allocator_len;
985  if ( full[offset] == '>') {
986  // done.
987  } else if (full[offset] == ' ' && full[offset+1] == '>') {
988  ++offset;
989  // done.
990  } else {
991  // Not std::string
992  isString = false;
993  }
994  }
995  } else {
996  // Not std::string
997  isString = false;
998  }
999  } else {
1000  // Not std::string.
1001  isString = false;
1002  }
1003  } else {
1004  // Not std::string.
1005  isString = false;
1006  }
1007  if (isString) {
1008  output.push_back(string());
1009  if (const_offset && (mode & kKeepOuterConst)) {
1010  if (isStdString && !(mode & kDropStd)) {
1011  output.push_back("const std::string");
1012  } else {
1013  output.push_back("const string");
1014  }
1015  } else {
1016  if (isStdString && !(mode & kDropStd)) {
1017  output.push_back("std::string");
1018  } else {
1019  output.push_back("string");
1020  }
1021  }
1022  if (offset < full.length()) {
1023  // Copy the trailing text.
1024  // keep the '>' inside right for R__FindTrailing to work
1025  string right( full.substr(offset) );
1026  string stars;
1027  R__FindTrailing(right, stars);
1028  output.back().append(right.c_str()+1); // skip the '>'
1029  output.push_back(stars);
1030  } else {
1031  output.push_back("");
1032  }
1033  return output.size();
1034  }
1035  }
1036  }
1037 
1038  if ( mode & kDropStd) {
1039  unsigned int offset = (0==strncmp("const ",full.c_str(),6)) ? 6 : 0;
1040  RemoveStd( full, offset );
1041  }
1042 
1043  string stars;
1044  if ( !full.empty() ) {
1045  R__FindTrailing(full, stars);
1046  }
1047 
1048  const char *c = strchr(full.c_str(),'<');
1049  if (c) {
1050  //we have 'something<'
1051  output.push_back(string(full,0,c - full.c_str()));
1052 
1053  const char *cursor;
1054  int level = 0;
1055  for(cursor = c + 1; *cursor != '\0' && !(level==0 && *cursor == '>'); ++cursor) {
1056  switch (*cursor) {
1057  case '<': ++level; break;
1058  case '>': --level; break;
1059  case ',':
1060  if (level == 0) {
1061  output.push_back(std::string(c+1,cursor));
1062  c = cursor;
1063  }
1064  break;
1065  }
1066  }
1067  if (*cursor=='>') {
1068  if (*(cursor-1) == ' ') {
1069  output.push_back(std::string(c+1,cursor-1));
1070  } else {
1071  output.push_back(std::string(c+1,cursor));
1072  }
1073  // See what's next!
1074  if (*(cursor+1)==':') {
1075  // we have a name specified inside the class/namespace
1076  // For now we keep it in one piece
1077  nestedLoc = output.size();
1078  output.push_back((cursor+1));
1079  }
1080  } else if (level >= 0) {
1081  // Unterminated template
1082  output.push_back(std::string(c+1,cursor));
1083  }
1084  } else {
1085  //empty
1086  output.push_back(string());
1087  output.push_back(full);
1088  }
1089 
1090  if (!output.empty()) output.push_back(stars);
1091  return output.size();
1092 }
1093 
1094 
1095 ////////////////////////////////////////////////////////////////////////////////
1096 ////////////////////////////////////////////////////////////////////////////
1097 /// Cleanup type description, redundant blanks removed
1098 /// and redundant tail ignored
1099 /// return *tail = pointer to last used character
1100 /// if (mode==0) keep keywords
1101 /// if (mode==1) remove keywords outside the template params
1102 /// if (mode>=2) remove the keywords everywhere.
1103 /// if (tail!=0) cut before the trailing *
1104 ///
1105 /// The keywords currently are: "const" , "volatile" removed
1106 ///
1107 ///
1108 /// CleanType(" A<B, C< D, E> > *,F,G>") returns "A<B,C<D,E> >*"
1109 ////////////////////////////////////////////////////////////////////////////
1110 
1111 string TClassEdit::CleanType(const char *typeDesc, int mode, const char **tail)
1112 {
1113  static const char* remove[] = {"class","const","volatile",0};
1114  static bool isinit = false;
1115  static std::vector<size_t> lengths;
1116  if (!isinit) {
1117  for (int k=0; remove[k]; ++k) {
1118  lengths.push_back(strlen(remove[k]));
1119  }
1120  isinit = true;
1121  }
1122 
1123  string result;
1124  result.reserve(strlen(typeDesc)*2);
1125  int lev=0,kbl=1;
1126  const char* c;
1127 
1128  for(c=typeDesc;*c;c++) {
1129  if (c[0]==' ') {
1130  if (kbl) continue;
1131  if (!isalnum(c[ 1]) && c[ 1] !='_') continue;
1132  }
1133  if (kbl && (mode>=2 || lev==0)) { //remove "const' etc...
1134  int done = 0;
1135  int n = (mode) ? 999 : 1;
1136 
1137  // loop on all the keywords we want to remove
1138  for (int k=0; k<n && remove[k]; k++) {
1139  int rlen = lengths[k];
1140 
1141  // Do we have a match
1142  if (strncmp(remove[k],c,rlen)) continue;
1143 
1144  // make sure that the 'keyword' is not part of a longer indentifier
1145  if (isalnum(c[rlen]) || c[rlen]=='_' || c[rlen]=='$') continue;
1146 
1147  c+=rlen-1; done = 1; break;
1148  }
1149  if (done) continue;
1150  }
1151 
1152  kbl = (!isalnum(c[ 0]) && c[ 0]!='_' && c[ 0]!='$' && c[0]!='[' && c[0]!=']' && c[0]!='-' && c[0]!='@');
1153  // '@' is special character used only the artifical class name used by ROOT to implement the
1154  // I/O customization rules that requires caching of the input data.
1155 
1156  if (*c == '<' || *c == '(') lev++;
1157  if (lev==0 && !isalnum(*c)) {
1158  if (!strchr("*&:._$ []-@",*c)) break;
1159  // '.' is used as a module/namespace separator by PyROOT, see
1160  // TPyClassGenerator::GetClass.
1161  }
1162  if (c[0]=='>' && result.size() && result[result.size()-1]=='>') result+=" ";
1163 
1164  result += c[0];
1165 
1166  if (*c == '>' || *c == ')') lev--;
1167  }
1168  if(tail) *tail=c;
1169  return result;
1170 }
1171 
1172 ////////////////////////////////////////////////////////////////////////////////
1173 //////////////////////////////////////////////////////////////////////////////
1174 /// Return the absolute type of typeDesc.
1175 /// E.g.: typeDesc = "class const volatile TNamed**", returns "TNamed**".
1176 /// if (mode&1) remove last "*"s returns "TNamed"
1177 /// if (mode&2) remove default allocators from STL containers
1178 /// if (mode&4) remove all allocators from STL containers
1179 /// if (mode&8) return inner class of stl container. list<innerClass>
1180 /// if (mode&16) return deapest class of stl container. vector<list<deapest>>
1181 /// if (mode&kDropAllDefault) remove default template arguments
1182 //////////////////////////////////////////////////////////////////////////////
1183 
1184 string TClassEdit::ShortType(const char *typeDesc, int mode)
1185 {
1186  string answer;
1187 
1188  // get list of all arguments
1189  if (typeDesc) {
1190  TSplitType arglist(typeDesc, (EModType) mode);
1191  arglist.ShortType(answer, mode);
1192  }
1193 
1194  return answer;
1195 }
1196 
1197 ////////////////////////////////////////////////////////////////////////////////
1198 /// Return true if the type is one the interpreter details which are
1199 /// only forward declared (ClassInfo_t etc..)
1200 
1202 {
1203  size_t len = strlen(type);
1204  if (len < 2 || strncmp(type+len-2,"_t",2) != 0) return false;
1205 
1206  unsigned char offset = 0;
1207  if (strncmp(type,"const ",6)==0) { offset += 6; }
1208  static const char *names[] = { "CallFunc_t","ClassInfo_t","BaseClassInfo_t",
1209  "DataMemberInfo_t","FuncTempInfo_t","MethodInfo_t","MethodArgInfo_t",
1210  "TypeInfo_t","TypedefInfo_t",0};
1211 
1212  for(int k=1;names[k];k++) {if (strcmp(type+offset,names[k])==0) return true;}
1213  return false;
1214 }
1215 
1216 ////////////////////////////////////////////////////////////////////////////////
1217 /// Return true is the name is std::bitset<number> or bitset<number>
1218 
1219 bool TClassEdit::IsSTLBitset(const char *classname)
1220 {
1221  size_t offset = StdLen(classname);
1222  if ( strncmp(classname+offset,"bitset<",strlen("bitset<"))==0) return true;
1223  return false;
1224 }
1225 
1226 ////////////////////////////////////////////////////////////////////////////////
1227 /// Return the type of STL collection, if any, that is the underlying type
1228 /// of the given type. Namely return the value of IsSTLCont after stripping
1229 /// pointer, reference and constness from the type.
1230 /// UnderlyingIsSTLCont("vector<int>*") == IsSTLCont("vector<int>")
1231 /// See TClassEdit::IsSTLCont
1232 ///
1233 /// type : type name: vector<list<classA,allocator>,allocator>*
1234 /// result: 0 : not stl container
1235 /// code of container 1=vector,2=list,3=deque,4=map
1236 /// 5=multimap,6=set,7=multiset
1237 
1239 {
1240  if (type.compare(0,6,"const ",6) == 0)
1241  type.remove_prefix(6);
1242 
1243  while(type[type.length()-1]=='*' ||
1244  type[type.length()-1]=='&' ||
1245  type[type.length()-1]==' ') {
1246  type.remove_suffix(1);
1247  }
1248  return IsSTLCont(type);
1249 }
1250 
1251 ////////////////////////////////////////////////////////////////////////////////
1252 /// type : type name: vector<list<classA,allocator>,allocator>
1253 /// result: 0 : not stl container
1254 /// code of container 1=vector,2=list,3=deque,4=map
1255 /// 5=multimap,6=set,7=multiset
1256 
1258 {
1259  auto pos = type.find('<');
1260  if (pos==std::string_view::npos) return ROOT::kNotSTL;
1261 
1262  auto c = pos+1;
1263  for (decltype(type.length()) level = 1; c < type.length(); ++c) {
1264  if (type[c] == '<') ++level;
1265  if (type[c] == '>') --level;
1266  if (level == 0) break;
1267  }
1268  if (c != (type.length()-1) ) {
1269  return ROOT::kNotSTL;
1270  }
1271 
1272  return STLKind({type.data(),pos});
1273 }
1274 
1275 ////////////////////////////////////////////////////////////////////////////////
1276 /// type : type name: vector<list<classA,allocator>,allocator>
1277 /// testAlloc: if true, we test allocator, if it is not default result is negative
1278 /// result: 0 : not stl container
1279 /// abs(result): code of container 1=vector,2=list,3=deque,4=map
1280 /// 5=multimap,6=set,7=multiset
1281 /// positive val: we have a vector or list with default allocator to any depth
1282 /// like vector<list<vector<int>>>
1283 /// negative val: STL container other than vector or list, or non default allocator
1284 /// For example: vector<deque<int>> has answer -1
1285 
1286 int TClassEdit::IsSTLCont(const char *type, int testAlloc)
1287 {
1288  if (strchr(type,'<')==0) return 0;
1289 
1290  TSplitType arglist( type );
1291  return arglist.IsSTLCont(testAlloc);
1292 }
1293 
1294 ////////////////////////////////////////////////////////////////////////////////
1295 /// return true if the class belongs to the std namespace
1296 
1297 bool TClassEdit::IsStdClass(const char *classname)
1298 {
1299  classname += StdLen( classname );
1300  if ( strcmp(classname,"string")==0 ) return true;
1301  if ( strncmp(classname,"bitset<",strlen("bitset<"))==0) return true;
1302  if ( strncmp(classname,"pair<",strlen("pair<"))==0) return true;
1303  if ( strcmp(classname,"allocator")==0) return true;
1304  if ( strncmp(classname,"allocator<",strlen("allocator<"))==0) return true;
1305  if ( strncmp(classname,"greater<",strlen("greater<"))==0) return true;
1306  if ( strncmp(classname,"less<",strlen("less<"))==0) return true;
1307  if ( strncmp(classname,"equal_to<",strlen("equal_to<"))==0) return true;
1308  if ( strncmp(classname,"hash<",strlen("hash<"))==0) return true;
1309  if ( strncmp(classname,"auto_ptr<",strlen("auto_ptr<"))==0) return true;
1310 
1311  if ( strncmp(classname,"vector<",strlen("vector<"))==0) return true;
1312  if ( strncmp(classname,"list<",strlen("list<"))==0) return true;
1313  if ( strncmp(classname,"forward_list<",strlen("forward_list<"))==0) return true;
1314  if ( strncmp(classname,"deque<",strlen("deque<"))==0) return true;
1315  if ( strncmp(classname,"map<",strlen("map<"))==0) return true;
1316  if ( strncmp(classname,"multimap<",strlen("multimap<"))==0) return true;
1317  if ( strncmp(classname,"set<",strlen("set<"))==0) return true;
1318  if ( strncmp(classname,"multiset<",strlen("multiset<"))==0) return true;
1319  if ( strncmp(classname,"unordered_set<",strlen("unordered_set<"))==0) return true;
1320  if ( strncmp(classname,"unordered_multiset<",strlen("unordered_multiset<"))==0) return true;
1321  if ( strncmp(classname,"unordered_map<",strlen("unordered_map<"))==0) return true;
1322  if ( strncmp(classname,"unordered_multimap<",strlen("unordered_multimap<"))==0) return true;
1323  if ( strncmp(classname,"bitset<",strlen("bitset<"))==0) return true;
1324 
1325  return false;
1326 }
1327 
1328 
1329 ////////////////////////////////////////////////////////////////////////////////
1330 
1331 bool TClassEdit::IsVectorBool(const char *name) {
1332  TSplitType splitname( name );
1333 
1334  return ( TClassEdit::STLKind( splitname.fElements[0] ) == ROOT::kSTLvector)
1335  && ( splitname.fElements[1] == "bool" || splitname.fElements[1]=="Bool_t");
1336 }
1337 
1338 ////////////////////////////////////////////////////////////////////////////////
1339 
1340 static void ResolveTypedefProcessType(const char *tname,
1341  unsigned int /* len */,
1342  unsigned int cursor,
1343  bool constprefix,
1344  unsigned int start_of_type,
1345  unsigned int end_of_type,
1346  unsigned int mod_start_of_type,
1347  bool &modified,
1348  std::string &result)
1349 {
1350  std::string type(modified && (mod_start_of_type < result.length()) ?
1351  result.substr(mod_start_of_type, string::npos)
1352  : string(tname, start_of_type, end_of_type == 0 ? cursor - start_of_type : end_of_type - start_of_type)); // we need to try to avoid this copy
1353  string typeresult;
1354  if (gInterpreterHelper->ExistingTypeCheck(type, typeresult)
1355  || gInterpreterHelper->GetPartiallyDesugaredNameWithScopeHandling(type, typeresult)) {
1356  // it is a known type
1357  if (!typeresult.empty()) {
1358  // and it is a typedef, we need to replace it in the output.
1359  if (modified) {
1360  result.replace(mod_start_of_type, string::npos,
1361  typeresult);
1362  }
1363  else {
1364  modified = true;
1365  mod_start_of_type = start_of_type;
1366  result += string(tname,0,start_of_type);
1367  if (constprefix && typeresult.compare(0,6,"const ",6) == 0) {
1368  result += typeresult.substr(6,string::npos);
1369  } else {
1370  result += typeresult;
1371  }
1372  }
1373  } else if (modified) {
1374  result.replace(mod_start_of_type, string::npos,
1375  type);
1376  }
1377  if (modified) {
1378  if (end_of_type != 0 && end_of_type!=cursor) {
1379  result += std::string(tname,end_of_type,cursor-end_of_type);
1380  }
1381  }
1382  } else {
1383  // no change needed.
1384  if (modified) {
1385  // result += type;
1386  if (end_of_type != 0 && end_of_type!=cursor) {
1387  result += std::string(tname,end_of_type,cursor-end_of_type);
1388  }
1389  }
1390  }
1391 }
1392 
1393 ////////////////////////////////////////////////////////////////////////////////
1394 
1395 static void ResolveTypedefImpl(const char *tname,
1396  unsigned int len,
1397  unsigned int &cursor,
1398  bool &modified,
1399  std::string &result)
1400 {
1401  // Need to parse and deal with
1402  // A::B::C< D, E::F, G::H<I,J>::K::L >::M
1403  // where E might be replace by N<O,P>
1404  // and G::H<I,J>::K or G might be a typedef.
1405 
1406  bool constprefix = false;
1407 
1408  if (tname[cursor]==' ') {
1409  if (!modified) {
1410  modified = true;
1411  result += string(tname,0,cursor);
1412  }
1413  while (tname[cursor]==' ') ++cursor;
1414  }
1415 
1416  if (tname[cursor]=='c' && (cursor+6<len)) {
1417  if (strncmp(tname+cursor,"const ",6) == 0) {
1418  cursor += 6;
1419  if (modified) result += "const ";
1420  }
1421  constprefix = true;
1422 
1423  }
1424 
1425  // When either of those two is true, we should probably go to modified
1426  // mode. (Otherwise we rely on somebody else to strip the std::)
1427  if (len > 5 && strncmp(tname+cursor,"std::",5) == 0) {
1428  cursor += 5;
1429  }
1430  if (len > 2 && strncmp(tname+cursor,"::",2) == 0) {
1431  cursor += 2;
1432  len -= 2;
1433  }
1434 
1435  unsigned int start_of_type = cursor;
1436  unsigned int end_of_type = 0;
1437  unsigned int mod_start_of_type = result.length();
1438  unsigned int prevScope = cursor;
1439  for ( ; cursor<len; ++cursor) {
1440  switch (tname[cursor]) {
1441  case ':': {
1442  if ((cursor+1)>=len || tname[cursor+1]!=':') {
1443  // we expected another ':', malformed, give up.
1444  if (modified) result += (tname+prevScope);
1445  return;
1446  }
1447  string scope;
1448  if (modified) {
1449  scope = result.substr(mod_start_of_type, string::npos);
1450  scope += std::string(tname+prevScope,cursor-prevScope);
1451  } else {
1452  scope = std::string(tname, start_of_type, cursor - start_of_type); // we need to try to avoid this copy
1453  }
1454  std::string scoperesult;
1455  bool isInlined = false;
1456  if (gInterpreterHelper->ExistingTypeCheck(scope, scoperesult)
1457  ||gInterpreterHelper->GetPartiallyDesugaredNameWithScopeHandling(scope, scoperesult)) {
1458  // it is a known type
1459  if (!scoperesult.empty()) {
1460  // and it is a typedef
1461  if (modified) {
1462  if (constprefix && scoperesult.compare(0,6,"const ",6) != 0) mod_start_of_type -= 6;
1463  result.replace(mod_start_of_type, string::npos,
1464  scoperesult);
1465  result += "::";
1466  } else {
1467  modified = true;
1468  mod_start_of_type = start_of_type;
1469  result += string(tname,0,start_of_type);
1470  //if (constprefix) result += "const ";
1471  result += scoperesult;
1472  result += "::";
1473  }
1474  } else if (modified) {
1475  result += std::string(tname+prevScope,cursor+1-prevScope);
1476  }
1477  } else if (!gInterpreterHelper->IsDeclaredScope(scope,isInlined)) {
1478  // the nesting namespace is not declared
1479  if (modified) result += (tname+prevScope);
1480  // Unfortunately, this is too harsh .. what about:
1481  // unknown::wrapper<Int_t>
1482  return;
1483  } else if (isInlined) {
1484  // humm ... just skip it.
1485  if (!modified) {
1486  modified = true;
1487  mod_start_of_type = start_of_type;
1488  result += string(tname,0,start_of_type);
1489  //if (constprefix) result += "const ";
1490  result += string(tname,start_of_type,prevScope - start_of_type);
1491  }
1492  } else if (modified) {
1493  result += std::string(tname+prevScope,cursor+1-prevScope);
1494  }
1495  // Consume the 1st semi colon, the 2nd will be consume by the for loop.
1496  ++cursor;
1497  prevScope = cursor+1;
1498  break;
1499  }
1500  case '<': {
1501  // push information on stack
1502  if (modified) {
1503  result += std::string(tname+prevScope,cursor+1-prevScope);
1504  // above includes the '<' .... result += '<';
1505  }
1506  do {
1507  ++cursor;
1508  ResolveTypedefImpl(tname,len,cursor,modified,result);
1509  } while( cursor<len && tname[cursor] == ',' );
1510 
1511  while (cursor<len && tname[cursor+1]==' ') ++cursor;
1512 
1513  // Since we already checked the type, skip the next section
1514  // (respective the scope section and final type processing section)
1515  // as they would re-do the same job.
1516  if (cursor+2<len && tname[cursor+1]==':' && tname[cursor+2]==':') {
1517  if (modified) result += "::";
1518  cursor += 2;
1519  prevScope = cursor+1;
1520  }
1521  if ( (cursor+1)<len && tname[cursor+1] == ',') {
1522  ++cursor;
1523  if (modified) result += ',';
1524  return;
1525  }
1526  if ( (cursor+1)<len && tname[cursor+1] == '>') {
1527  ++cursor;
1528  if (modified) result += " >";
1529  return;
1530  }
1531  if ( (cursor+1) >= len) {
1532  return;
1533  }
1534  if (tname[cursor] != ' ') break;
1535  if (modified) prevScope = cursor+1;
1536  // If the 'current' character is a space we need to treat it,
1537  // since this the next case statement, we can just fall through,
1538  // otherwise we should need to do:
1539  // --cursor; break;
1540  }
1541  case ' ': {
1542  end_of_type = cursor;
1543  // let's see if we have 'long long' or 'unsigned int' or 'signed char' or what not.
1544  while ((cursor+1)<len && tname[cursor+1] == ' ') ++cursor;
1545 
1546  auto next = cursor+1;
1547  if (strncmp(tname+next,"const",5) == 0 && ((next+5)==len || tname[next+5] == ' ' || tname[next+5] == '*' || tname[next+5] == '&' || tname[next+5] == ',' || tname[next+5] == '>' || tname[next+5] == ']'))
1548  {
1549  // A first const after the type needs to be move in the front.
1550  if (!modified) {
1551  modified = true;
1552  result += string(tname,0,start_of_type);
1553  result += "const ";
1554  mod_start_of_type = start_of_type + 6;
1555  result += string(tname,start_of_type,end_of_type-start_of_type);
1556  } else if (mod_start_of_type < result.length()) {
1557  result.insert(mod_start_of_type,"const ");
1558  mod_start_of_type += 6;
1559  } else {
1560  result += "const ";
1561  mod_start_of_type += 6;
1562  result += string(tname,start_of_type,end_of_type-start_of_type);
1563  }
1564  cursor += 5;
1565  end_of_type = cursor+1;
1566  prevScope = end_of_type;
1567  if (tname[next+5] == ',' || tname[next+5] == '>' || tname[next+5] == '[') {
1568  break;
1569  }
1570  } else if (next!=len && tname[next] != '*' && tname[next] != '&') {
1571  // the type is not ended yet.
1572  end_of_type = 0;
1573  break;
1574  }
1575  ++cursor;
1576  // Intentional fall through;
1577  }
1578  case '*':
1579  case '&': {
1580  if (tname[cursor] != ' ') end_of_type = cursor;
1581  // check and skip const (followed by *,&, ,) ... what about followed by ':','['?
1582  auto next = cursor+1;
1583  if (strncmp(tname+next,"const",5) == 0) {
1584  if ((next+5)==len || tname[next+5] == ' ' || tname[next+5] == '*' || tname[next+5] == '&' || tname[next+5] == ',' || tname[next+5] == '>' || tname[next+5] == '[') {
1585  next += 5;
1586  }
1587  }
1588  while (next<len &&
1589  (tname[next] == ' ' || tname[next] == '*' || tname[next] == '&')) {
1590  ++next;
1591  // check and skip const (followed by *,&, ,) ... what about followed by ':','['?
1592  if (strncmp(tname+next,"const",5) == 0) {
1593  if ((next+5)==len || tname[next+5] == ' ' || tname[next+5] == '*' || tname[next+5] == '&' || tname[next+5] == ',' || tname[next+5] == '>' || tname[next+5] == '[') {
1594  next += 5;
1595  }
1596  }
1597  }
1598  cursor = next-1;
1599 // if (modified && mod_start_of_type < result.length()) {
1600 // result += string(tname,end_of_type,cursor-end_of_type);
1601 // }
1602  break;
1603  }
1604  case ',': {
1605  if (modified && prevScope) {
1606  result += std::string(tname+prevScope,(end_of_type == 0 ? cursor : end_of_type)-prevScope);
1607  }
1608  ResolveTypedefProcessType(tname,len,cursor,constprefix,start_of_type,end_of_type,mod_start_of_type,
1609  modified, result);
1610  if (modified) result += ',';
1611  return;
1612  }
1613  case '>': {
1614  if (modified && prevScope) {
1615  result += std::string(tname+prevScope,(end_of_type == 0 ? cursor : end_of_type)-prevScope);
1616  }
1617  ResolveTypedefProcessType(tname,len,cursor,constprefix,start_of_type,end_of_type,mod_start_of_type,
1618  modified, result);
1619  if (modified) result += '>';
1620  return;
1621  }
1622  default:
1623  end_of_type = 0;
1624  }
1625  }
1626 
1627  if (prevScope && modified) result += std::string(tname+prevScope,(end_of_type == 0 ? cursor : end_of_type)-prevScope);
1628 
1629  ResolveTypedefProcessType(tname,len,cursor,constprefix,start_of_type,end_of_type,mod_start_of_type,
1630  modified, result);
1631 }
1632 
1633 
1634 ////////////////////////////////////////////////////////////////////////////////
1635 
1636 string TClassEdit::ResolveTypedef(const char *tname, bool /* resolveAll */)
1637 {
1638  // Return the name of type 'tname' with all its typedef components replaced
1639  // by the actual type its points to
1640  // For example for "typedef MyObj MyObjTypedef;"
1641  // vector<MyObjTypedef> return vector<MyObj>
1642  //
1643 
1644  if ( tname==0 || tname[0]==0 || !gInterpreterHelper) return "";
1645 
1646  std::string result;
1647 
1648  // Check if we already know it is a normalized typename or a registered
1649  // typedef (i.e. known to gROOT).
1650  if (gInterpreterHelper->ExistingTypeCheck(tname, result))
1651  {
1652  if (result.empty()) return tname;
1653  else return result;
1654  }
1655 
1656  unsigned int len = strlen(tname);
1657 
1658  unsigned int cursor = 0;
1659  bool modified = false;
1660  ResolveTypedefImpl(tname,len,cursor,modified,result);
1661 
1662  if (!modified) return tname;
1663  else return result;
1664 }
1665 
1666 
1667 ////////////////////////////////////////////////////////////////////////////////
1668 
1669 string TClassEdit::InsertStd(const char *tname)
1670 {
1671  // Return the name of type 'tname' with all STL classes prepended by "std::".
1672  // For example for "vector<set<auto_ptr<int*> > >" it returns
1673  // "std::vector<std::set<std::auto_ptr<int*> > >"
1674  //
1675 
1676  static const char* sSTLtypes[] = {
1677  "allocator",
1678  "auto_ptr",
1679  "bad_alloc",
1680  "bad_cast",
1681  "bad_exception",
1682  "bad_typeid",
1683  "basic_filebuf",
1684  "basic_fstream",
1685  "basic_ifstream",
1686  "basic_ios",
1687  "basic_iostream",
1688  "basic_istream",
1689  "basic_istringstream",
1690  "basic_ofstream",
1691  "basic_ostream",
1692  "basic_ostringstream",
1693  "basic_streambuf",
1694  "basic_string",
1695  "basic_stringbuf",
1696  "basic_stringstream",
1697  "binary_function",
1698  "binary_negate",
1699  "bitset",
1700  "char_traits",
1701  "codecvt_byname",
1702  "codecvt",
1703  "collate",
1704  "collate_byname",
1705  "compare",
1706  "complex",
1707  "ctype_byname",
1708  "ctype",
1709  "deque",
1710  "divides",
1711  "domain_error",
1712  "equal_to",
1713  "exception",
1714  "forward_list",
1715  "fpos",
1716  "greater_equal",
1717  "greater",
1718  "gslice_array",
1719  "gslice",
1720  "hash",
1721  "indirect_array",
1722  "invalid_argument",
1723  "ios_base",
1724  "istream_iterator",
1725  "istreambuf_iterator",
1726  "istrstream",
1727  "iterator_traits",
1728  "iterator",
1729  "length_error",
1730  "less_equal",
1731  "less",
1732  "list",
1733  "locale",
1734  "localedef utility",
1735  "locale utility",
1736  "logic_error",
1737  "logical_and",
1738  "logical_not",
1739  "logical_or",
1740  "map",
1741  "mask_array",
1742  "mem_fun",
1743  "mem_fun_ref",
1744  "messages",
1745  "messages_byname",
1746  "minus",
1747  "modulus",
1748  "money_get",
1749  "money_put",
1750  "moneypunct",
1751  "moneypunct_byname",
1752  "multimap",
1753  "multiplies",
1754  "multiset",
1755  "negate",
1756  "not_equal_to",
1757  "num_get",
1758  "num_put",
1759  "numeric_limits",
1760  "numpunct",
1761  "numpunct_byname",
1762  "ostream_iterator",
1763  "ostreambuf_iterator",
1764  "ostrstream",
1765  "out_of_range",
1766  "overflow_error",
1767  "pair",
1768  "plus",
1769  "pointer_to_binary_function",
1770  "pointer_to_unary_function",
1771  "priority_queue",
1772  "queue",
1773  "range_error",
1774  "raw_storage_iterator",
1775  "reverse_iterator",
1776  "runtime_error",
1777  "set",
1778  "slice_array",
1779  "slice",
1780  "stack",
1781  "string",
1782  "strstream",
1783  "strstreambuf",
1784  "time_get_byname",
1785  "time_get",
1786  "time_put_byname",
1787  "time_put",
1788  "unary_function",
1789  "unary_negate",
1790  "underflow_error",
1791  "unordered_map",
1792  "unordered_multimap",
1793  "unordered_multiset",
1794  "unordered_set",
1795  "valarray",
1796  "vector",
1797  "wstring"
1798  };
1799  static set<string> sSetSTLtypes;
1800 
1801  if (tname==0 || tname[0]==0) return "";
1802 
1803  if (sSetSTLtypes.empty()) {
1804  // set up static set
1805  const size_t nSTLtypes = sizeof(sSTLtypes) / sizeof(const char*);
1806  for (size_t i = 0; i < nSTLtypes; ++i)
1807  sSetSTLtypes.insert(sSTLtypes[i]);
1808  }
1809 
1810  size_t b = 0;
1811  size_t len = strlen(tname);
1812  string ret;
1813  ret.reserve(len + 20); // expect up to 4 extra "std::" to insert
1814  string id;
1815  while (b < len) {
1816  // find beginning of next identifier
1817  bool precScope = false; // whether the identifier was preceded by "::"
1818  while (!(isalnum(tname[b]) || tname[b] == '_') && b < len) {
1819  precScope = (b < len - 2) && (tname[b] == ':') && (tname[b + 1] == ':');
1820  if (precScope) {
1821  ret += "::";
1822  b += 2;
1823  } else
1824  ret += tname[b++];
1825  }
1826 
1827  // now b is at the beginning of an identifier or len
1828  size_t e = b;
1829  // find end of identifier
1830  id.clear();
1831  while (e < len && (isalnum(tname[e]) || tname[e] == '_'))
1832  id += tname[e++];
1833  if (!id.empty()) {
1834  if (!precScope) {
1835  set<string>::const_iterator iSTLtype = sSetSTLtypes.find(id);
1836  if (iSTLtype != sSetSTLtypes.end())
1837  ret += "std::";
1838  }
1839 
1840  ret += id;
1841  b = e;
1842  }
1843  }
1844  return ret;
1845 }
1846 
1847 ////////////////////////////////////////////////////////////////////////////////
1848 /// Demangle in a portable way the type id name.
1849 /// IMPORTANT: The caller is responsible for freeing the returned const char*
1850 
1851 char* TClassEdit::DemangleTypeIdName(const std::type_info& ti, int& errorCode)
1852 {
1853  const char* mangled_name = ti.name();
1854  return DemangleName(mangled_name, errorCode);
1855 }
static size_t StdLen(const std::string_view name)
Return the length, if any, taken by std:: and any potential inline namespace (well compiler detail na...
Definition: TClassEdit.cxx:27
ESTLType
Definition: ESTLType.h:28
ROOT::ESTLType IsSTLCont(std::string_view type)
type : type name: vector<list<classA,allocator>,allocator> result: 0 : not stl container code of cont...
int IsSTLCont(int testAlloc=0) const
type : type name: vector<list<classA,allocator>,allocator> testAlloc: if true, we test allocator...
Definition: TClassEdit.cxx:153
ClassImp(TSeqCollection) Int_t TSeqCollection TIter next(this)
Return index of object in collection.
TSplitType(const char *type2split, EModType mode=TClassEdit::kNone)
default constructor
Definition: TClassEdit.cxx:126
return c
_LIBCPP_CONSTEXPR _LIBCPP_INLINE_VISIBILITY size_type length() const _NOEXCEPT
tuple offset
Definition: tree.py:93
int GetSplit(const char *type, std::vector< std::string > &output, int &nestedLoc, EModType mode=TClassEdit::kNone)
Stores in output (after emptying it) the splited type.
Definition: TClassEdit.cxx:927
ROOT::ESTLType IsInSTL() const
type : type name: vector<list<classA,allocator>,allocator>[::iterator] result: 0 : not stl container ...
Definition: TClassEdit.cxx:136
#define assert(cond)
Definition: unittest.h:542
std::vector< double > values
Definition: TwoHistoFit2D.C:32
bool IsDefAlloc(const char *alloc, const char *classname)
return whether or not 'allocname' is the STL default allocator for type 'classname' ...
Definition: TClassEdit.cxx:556
int compare(double v1, double v2, const std::string &name="", double scale=1.0)
std::string CleanType(const char *typeDesc, int mode=0, const char **tail=0)
Cleanup type description, redundant blanks removed and redundant tail ignored return *tail = pointer ...
std::string InsertStd(const char *tname)
TArc * a
Definition: textangle.C:12
static void RemoveStd(std::string &name, size_t pos=0)
Remove std:: and any potential inline namespace (well compiler detail namespace.
Definition: TClassEdit.cxx:74
bool IsSTLBitset(const char *type)
Return true is the name is std::bitset<number> or bitset<number>
int STLArgs(int kind)
Return number of arguments for STL container before allocator.
Definition: TClassEdit.cxx:511
void ShortType(std::string &answer, int mode)
Return the absolute type of typeDesc into the string answ.
Definition: TClassEdit.cxx:197
char * DemangleName(const char *mangled_name, int &errorCode)
Definition: TClassEdit.h:178
void Init(TClassEdit::TInterpreterLookupHelper *helper)
Definition: TClassEdit.cxx:118
std::string ResolveTypedef(const char *tname, bool resolveAll=false)
ROOT::ESTLType STLKind(std::string_view type)
Converts STL container name to number.
Definition: TClassEdit.cxx:467
static size_t findNameEnd(const std::string_view full)
Definition: TClassEdit.cxx:524
char * DemangleTypeIdName(const std::type_info &ti, int &errorCode)
Demangle in a portable way the type id name.
XFontStruct * id
Definition: TGX11.cxx:108
bool IsInterpreterDetail(const char *type)
Return true if the type is one the interpreter details which are only forward declared (ClassInfo_t e...
std::string GetLong64_Name(const char *original)
Replace 'long long' and 'unsigned long long' by 'Long64_t' and 'ULong64_t'.
Definition: TClassEdit.cxx:806
ROOT::ESTLType UnderlyingIsSTLCont(std::string_view type)
Return the type of STL collection, if any, that is the underlying type of the given type...
EComplexType GetComplexType(const char *)
Definition: TClassEdit.cxx:96
static void ResolveTypedefProcessType(const char *tname, unsigned int, unsigned int cursor, bool constprefix, unsigned int start_of_type, unsigned int end_of_type, unsigned int mod_start_of_type, bool &modified, std::string &result)
bool IsDefHash(const char *hashname, const char *classname)
return whether or not 'hashname' is the STL default hash for type 'classname'
Definition: TClassEdit.cxx:762
static void R__FindTrailing(std::string &full, std::string &stars)
Definition: TClassEdit.cxx:860
TThread * t[5]
Definition: threadsh1.C:13
_LIBCPP_CONSTEXPR_AFTER_CXX11 int compare(basic_string_view __sv) const _NOEXCEPT
std::vector< std::string > fElements
Definition: TClassEdit.h:139
return
Definition: TBase64.cxx:62
SVector< double, 2 > v
Definition: Dict.h:5
void GetNormalizedName(std::string &norm_name, std::string_view name)
Return the normalized name.
Definition: TClassEdit.cxx:777
bool IsVectorBool(const char *name)
const Handle_t kNone
Definition: GuiTypes.h:89
bool IsStdClass(const char *type)
return true if the class belongs to the std namespace
int type
Definition: TGX11.cxx:120
bool IsDefComp(const char *comp, const char *classname)
return whether or not 'compare' is the STL default comparator for type 'classname' ...
Definition: TClassEdit.cxx:744
_LIBCPP_CONSTEXPR _LIBCPP_INLINE_VISIBILITY const_pointer data() const _NOEXCEPT
#define name(a, b)
Definition: linkTestLib0.cpp:5
static bool IsDefElement(const char *elementName, const char *defaultElementName, const char *classname)
return whether or not 'elementName' is the STL default Element for type 'classname' ...
Definition: TClassEdit.cxx:702
const char * GetUnqualifiedName(const char *name)
Return the start of the unqualified name include in 'original'.
Definition: TClassEdit.cxx:840
std::string ShortType(const char *typeDesc, int mode)
Return the absolute type of typeDesc.
double result[121]
static void output(int code)
Definition: gifencode.c:226
const Int_t n
Definition: legend1.C:16
static void ResolveTypedefImpl(const char *tname, unsigned int len, unsigned int &cursor, bool &modified, std::string &result)
bool IsDefPred(const char *predname, const char *classname)
return whether or not 'predname' is the STL default predicate for type 'classname' ...
Definition: TClassEdit.cxx:753
_LIBCPP_CONSTEXPR_AFTER_CXX11 _LIBCPP_INLINE_VISIBILITY void remove_prefix(size_type __n) _NOEXCEPT