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 ------------------------------------------------------------------
10static inline
11bool is_varchar(char c) {
12 return isalnum((int)c) || c == '_' || c == ')' || c == '(' /* for (anonymous) */;
13}
14
15static inline
16std::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
33static 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
56static 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//----------------------------------------------------------------------------
71std::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)
116 else
118 }
119
120 return name;
121}
122
123//----------------------------------------------------------------------------
124std::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//----------------------------------------------------------------------------
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//----------------------------------------------------------------------------
159std::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//----------------------------------------------------------------------------
187std::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
#define c(i)
Definition: RSha256.hxx:101
char name[80]
Definition: TGX11.cxx:109
static void rstrip(std::string &name)
Definition: TypeManip.cxx:56
static std::string::size_type find_qualifier_index(const std::string &name)
Definition: TypeManip.cxx:16
static void erase_const(std::string &name)
Definition: TypeManip.cxx:33
static bool is_varchar(char c)
Definition: TypeManip.cxx:11
std::string remove_const(const std::string &cppname)
Definition: TypeManip.cxx:71
std::string template_base(const std::string &cppname)
Definition: TypeManip.cxx:124
void cppscope_to_pyscope(std::string &cppscope)
Definition: TypeManip.cxx:148
std::string clean_type(const std::string &cppname, bool template_strip=true, bool const_strip=true)
Definition: TypeManip.cxx:98
std::string extract_namespace(const std::string &name)
Definition: TypeManip.cxx:159
std::vector< std::string > extract_arg_types(const std::string &sig)
Definition: TypeManip.cxx:187