Logo ROOT  
Reference Guide
TypeManip.cxx
Go to the documentation of this file.
1 // Bindings
2 #include "CPyCppyy.h"
3 #include "TypeManip.h"
4 
5 // Standard
6 #include <ctype.h>
7 
8 
9 //- helpers ------------------------------------------------------------------
10 static inline
11 bool is_varchar(char c) {
12  return isalnum((int)c) || c == '_' || c == ')' || c == '(' /* for (anonymous) */;
13 }
14 
15 static inline
16 std::string::size_type find_qualifier_index(const std::string& name)
17 {
18 // Find the first location that is not part of the class name proper.
19  std::string::size_type i = name.size() - 1;
20  for ( ; 0 < i; --i) {
21  std::string::value_type c = name[i];
22  if (is_varchar(c) || c == '>') {
23  if (c == 't' && 6 < i && !is_varchar(name[i-5]) && name.substr(i-4, 5) == "const")
24  i -= 4; // this skips 'const' on a pointer type
25  else
26  break;
27  }
28  }
29 
30  return i+1;
31 }
32 
33 static inline void erase_const(std::string& name)
34 {
35 // Find and remove all occurrence of 'const'.
36  std::string::size_type spos = std::string::npos;
37  std::string::size_type start = 0;
38  while ((spos = name.find("const", start)) != std::string::npos) {
39  // make sure not to erase 'const' as part of the name: if it is
40  // connected, before or after, to a variable name, then keep it
41  std::string::size_type after = spos+5;
42  if (after < name.size() && is_varchar(name[after])) {
43  start = after;
44  continue;
45  } else if (after == name.size()) {
46  if (spos > 0 && is_varchar(name[spos - 1]))
47  break;
48  }
49 
50  std::string::size_type i = 5;
51  while (name[spos+i] == ' ') ++i;
52  name.swap(name.erase(spos, i));
53  }
54 }
55 
56 static inline void rstrip(std::string& name)
57 {
58 // Remove space from the right side of name.
59  std::string::size_type i = name.size();
60  for ( ; 0 < i; --i) {
61  if (!isspace(name[i]))
62  break;
63  }
64 
65  if (i != name.size())
66  name = name.substr(0, i);
67 }
68 
69 
70 //----------------------------------------------------------------------------
71 std::string CPyCppyy::TypeManip::remove_const(const std::string& cppname)
72 {
73 // Remove 'const' qualifiers from the given C++ name.
74  std::string::size_type tmplt_start = cppname.find('<');
75  std::string::size_type type_stop = cppname.rfind('>');
76  if (cppname.find("::", type_stop+1) != std::string::npos) // e.g. klass<T>::some_typedef
77  type_stop = cppname.find(' ', type_stop+1);
78  if (tmplt_start != std::string::npos) {
79  // only replace const qualifying cppname, not in template parameters
80  std::string pre = cppname.substr(0, tmplt_start);
81  erase_const(pre);
82  std::string post = "";
83  if (type_stop != std::string::npos) {
84  post = cppname.substr(type_stop+1, std::string::npos);
85  erase_const(post);
86  }
87 
88  type_stop = type_stop == std::string::npos ? std::string::npos : type_stop+1;
89  return pre + cppname.substr(tmplt_start, type_stop) + post;
90  }
91 
92  std::string clean_name = cppname;
93  erase_const(clean_name);
94  return clean_name;
95 }
96 
97 //----------------------------------------------------------------------------
99  const std::string& cppname, bool template_strip, bool const_strip)
100 {
101 // Strip C++ name from all qualifiers and compounds.
102  std::string::size_type i = find_qualifier_index(cppname);
103  std::string name = cppname.substr(0, i);
104  rstrip(name);
105 
106  if (name.back() == ']') { // array type?
107  // TODO: this fails templates instantiated on arrays (not common)
108  name = name.substr(0, name.find('['));
109  } else if (template_strip && name.back() == '>') {
110  name = name.substr(0, name.find('<'));
111  }
112 
113  if (const_strip) {
114  if (template_strip)
115  erase_const(name);
116  else
118  }
119 
120  return name;
121 }
122 
123 //----------------------------------------------------------------------------
124 std::string CPyCppyy::TypeManip::template_base(const std::string& cppname)
125 {
126 // If this is a template, return the underlying template name w/o arguments
127  if (cppname.empty() || cppname.back() != '>')
128  return cppname;
129 
130  int tpl_open = 0;
131  for (std::string::size_type pos = cppname.size()-1; 0 < pos; --pos) {
132  std::string::value_type c = cppname[pos];
133 
134  // count '<' and '>' to be able to skip template contents
135  if (c == '>')
136  ++tpl_open;
137  else if (c == '<')
138  --tpl_open;
139 
140  if (tpl_open == 0)
141  return cppname.substr(0, pos);
142  }
143 
144  return cppname;
145 }
146 
147 //----------------------------------------------------------------------------
148 void CPyCppyy::TypeManip::cppscope_to_pyscope(std::string& cppscope)
149 {
150 // Change '::' in C++ scope into '.' as in a Python scope.
151  std::string::size_type pos = 0;
152  while ((pos = cppscope.find("::", pos)) != std::string::npos) {
153  cppscope.replace(pos, 2, ".");
154  pos += 1;
155  }
156 }
157 
158 //----------------------------------------------------------------------------
159 std::string CPyCppyy::TypeManip::extract_namespace(const std::string& name)
160 {
161 // Find the namespace the named class lives in, take care of templates
162  if (name.empty())
163  return name;
164 
165  int tpl_open = 0;
166  for (std::string::size_type pos = name.size()-1; 0 < pos; --pos) {
167  std::string::value_type c = name[pos];
168 
169  // count '<' and '>' to be able to skip template contents
170  if (c == '>')
171  ++tpl_open;
172  else if (c == '<')
173  --tpl_open;
174 
175  // collect name up to "::"
176  else if (tpl_open == 0 && c == ':' && name[pos-1] == ':') {
177  // found the extend of the scope ... done
178  return name.substr(0, pos-1);
179  }
180  }
181 
182 // no namespace; assume outer scope
183  return "";
184 }
185 
186 //----------------------------------------------------------------------------
187 std::vector<std::string> CPyCppyy::TypeManip::extract_arg_types(const std::string& sig)
188 {
189 // break out the argument types from the signature string
190  std::vector<std::string> result;
191 
192  if (sig.empty() || sig == "()")
193  return result;
194 
195  int tpl_open = 0;
196  std::string::size_type start = 1;
197  for (std::string::size_type pos = 1; pos < sig.size()-1; ++pos) {
198  std::string::value_type c = sig[pos];
199 
200  // count '<' and '>' to be able to skip template contents
201  if (c == '>')
202  ++tpl_open;
203  else if (c == '<')
204  --tpl_open;
205 
206  // collect type name up to ',' or end ')'
207  else if (tpl_open == 0 && c == ',') {
208  // found the extend of the scope ... done
209  result.push_back(sig.substr(start, pos-start));
210  start = pos+1;
211  }
212  }
213 
214 // add last type
215  result.push_back(sig.substr(start, sig.rfind(")")-start));
216 
217  return result;
218 }
219 
void cppscope_to_pyscope(std::string &cppscope)
Definition: TypeManip.cxx:148
static void rstrip(std::string &name)
Definition: TypeManip.cxx:56
std::string extract_namespace(const std::string &name)
Definition: TypeManip.cxx:159
std::string template_base(const std::string &cppname)
Definition: TypeManip.cxx:124
static std::string::size_type find_qualifier_index(const std::string &name)
Definition: TypeManip.cxx:16
std::string clean_type(const std::string &cppname, bool template_strip=true, bool const_strip=true)
Definition: TypeManip.cxx:98
static void erase_const(std::string &name)
Definition: TypeManip.cxx:33
static bool is_varchar(char c)
Definition: TypeManip.cxx:11
#define c(i)
Definition: RSha256.hxx:101
std::string remove_const(const std::string &cppname)
Definition: TypeManip.cxx:71
char name[80]
Definition: TGX11.cxx:109
std::vector< std::string > extract_arg_types(const std::string &sig)
Definition: TypeManip.cxx:187