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