Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TypeManip.cxx
Go to the documentation of this file.
1// Bindings
2#include "CPyCppyy.h"
3#include "TypeManip.h"
4
5// Standard
6#include <algorithm>
7#include <sstream>
8#include <ctype.h>
9
10
11//- helpers ------------------------------------------------------------------
12static inline
13bool is_varchar(char c) {
14 return isalnum((int)c) || c == '_' || c == ')' || c == '(' /* for (anonymous)/(unnamed) */;
15}
16
17static inline
18std::string::size_type find_qualifier_index(const std::string& name)
19{
20// Find the first location that is not part of the class name proper.
21 std::string::size_type i = name.size() - 1;
22 bool arr_open = false;
23 for ( ; 0 < i; --i) {
24 std::string::value_type c = name[i];
25 if (!arr_open && (is_varchar(c) || c == '>')) {
26 if (c == 't' && 6 < i && !is_varchar(name[i-5]) && name.substr(i-4, 5) == "const")
27 i -= 4; // this skips 'const' on a pointer type
28 else
29 break;
30 } else if (c == ']') {
31 arr_open = true;
32 } else if (c == '[') {
33 arr_open = false;
34 }
35 }
36
37 return i+1;
38}
39
40static inline void erase_const(std::string& name)
41{
42// Find and remove all occurrence of 'const'.
43 if (name.empty())
44 return;
45
46 std::string::size_type spos = std::string::npos;
47 std::string::size_type start = 0;
48 while ((spos = name.find("const", start)) != std::string::npos) {
49 // make sure not to erase 'const' as part of the name: if it is
50 // connected, before or after, to a variable name, then keep it
51 std::string::size_type after = spos+5;
52 if (after < name.size() && is_varchar(name[after])) {
53 start = after;
54 continue;
55 } else if (after == name.size()) {
56 if (spos > 0 && is_varchar(name[spos - 1]))
57 break;
58 }
59
60 std::string::size_type i = 5;
61 while (name[spos+i] == ' ') ++i;
62 name.swap(name.erase(spos, i));
63 }
64}
65
66static inline void rstrip(std::string& name)
67{
68// Remove space from the right side of name.
69 std::string::size_type i = name.size();
70 for ( ; 0 < i; --i) {
71 if (!isspace(name[i-1]))
72 break;
73 }
74
75 if (i != name.size())
76 name = name.substr(0, i);
77}
78
79//----------------------------------------------------------------------------
80std::string CPyCppyy::TypeManip::remove_const(const std::string& cppname)
81{
82// Remove 'const' qualifiers from the given C++ name.
83 std::string::size_type tmplt_start = cppname.find('<');
84 std::string::size_type type_stop = cppname.rfind('>');
85 if (cppname.find("::", type_stop+1) != std::string::npos) // e.g. klass<T>::some_typedef
86 type_stop = cppname.find(' ', type_stop+1);
87 if (tmplt_start != std::string::npos && cppname[tmplt_start+1] != '<') {
88 // only replace const qualifying cppname, not in template parameters
89 std::string pre = cppname.substr(0, tmplt_start);
90 erase_const(pre);
91 std::string post = "";
92 if (type_stop != std::string::npos && type_stop != cppname.size()-1) {
93 post = cppname.substr(type_stop+1, std::string::npos);
94 erase_const(post);
95 }
96
97 return pre + cppname.substr(tmplt_start, type_stop+1-tmplt_start) + post;
98 }
99
100 std::string clean_name = cppname;
101 erase_const(clean_name);
102 return clean_name;
103}
104
105//----------------------------------------------------------------------------
107 const std::string& cppname, bool template_strip, bool const_strip)
108{
109// Strip C++ name from all qualifiers and compounds.
110 std::string::size_type i = find_qualifier_index(cppname);
111 std::string name = cppname.substr(0, i);
112 rstrip(name);
113
114 if (name.back() == ']') { // array type?
115 // TODO: this fails templates instantiated on arrays (not common)
116 name = name.substr(0, name.find('['));
117 } else if (template_strip && name.back() == '>') {
118 name = name.substr(0, name.find('<'));
119 }
120
121 if (const_strip) {
122 if (template_strip)
124 else
126 }
127
128 return name;
129}
130
131//----------------------------------------------------------------------------
132std::string CPyCppyy::TypeManip::template_base(const std::string& cppname)
133{
134// If this is a template, return the underlying template name w/o arguments
135 if (cppname.empty() || cppname.back() != '>')
136 return cppname;
137
138 int tpl_open = 0;
139 for (std::string::size_type pos = cppname.size()-1; 0 < pos; --pos) {
140 std::string::value_type c = cppname[pos];
141
142 // count '<' and '>' to be able to skip template contents
143 if (c == '>')
144 --tpl_open;
145 else if (c == '<' && cppname[pos+1] != '<')
146 ++tpl_open;
147
148 if (tpl_open == 0)
149 return cppname.substr(0, pos);
150 }
151
152 return cppname;
153}
154
155//----------------------------------------------------------------------------
156std::string CPyCppyy::TypeManip::compound(const std::string& name)
157{
158// Break down the compound of a fully qualified type name.
159 std::string cleanName = remove_const(name);
160 auto idx = find_qualifier_index(cleanName);
161
162 const std::string& cpd = cleanName.substr(idx, std::string::npos);
163
164// for easy identification of fixed size arrays
165 if (!cpd.empty() && cpd.back() == ']') {
166 if (cpd.front() == '[')
167 return "[]"; // fixed array any; dimensions handled separately
168
169 std::ostringstream scpd;
170 scpd << cpd.substr(0, cpd.find('[')) << "[]";
171 return scpd.str();
172 }
173
174 return cpd;
175}
176
177//----------------------------------------------------------------------------
179{
180// Change '::' in C++ scope into '.' as in a Python scope.
181 std::string::size_type pos = 0;
182 while ((pos = cppscope.find("::", pos)) != std::string::npos) {
183 cppscope.replace(pos, 2, ".");
184 pos += 1;
185 }
186}
187
188//----------------------------------------------------------------------------
190{
191// Change characters illegal in a variable name into '_' to form a legal name.
192 for (char& c : cppscope) {
193 for (char needle : {':', '>', '<', ' ', ',', '&', '='})
194 if (c == needle) c = '_';
195 }
196}
197
198//----------------------------------------------------------------------------
199std::string CPyCppyy::TypeManip::extract_namespace(const std::string& name)
200{
201// Find the namespace the named class lives in, take care of templates
202 if (name.empty())
203 return name;
204
205 int tpl_open = 0;
206 for (std::string::size_type pos = name.size()-1; 0 < pos; --pos) {
207 std::string::value_type c = name[pos];
208
209 // count '<' and '>' to be able to skip template contents
210 if (c == '>')
211 --tpl_open;
212 else if (c == '<' && name[pos+1] != '<')
213 ++tpl_open;
214
215 // collect name up to "::"
216 else if (tpl_open == 0 && c == ':' && name[pos-1] == ':') {
217 // found the extend of the scope ... done
218 return name.substr(0, pos-1);
219 }
220 }
221
222// no namespace; assume outer scope
223 return "";
224}
225
226//----------------------------------------------------------------------------
227std::vector<std::string> CPyCppyy::TypeManip::extract_arg_types(const std::string& sig)
228{
229// break out the argument types from the signature string
230 std::vector<std::string> result;
231
232 if (sig.empty() || sig == "()")
233 return result;
234
235 int tpl_open = 0;
236 std::string::size_type start = 1;
237 for (std::string::size_type pos = 1; pos < sig.size()-1; ++pos) {
238 std::string::value_type c = sig[pos];
239
240 // count '<' and '>' to be able to skip template contents
241 if (c == '>')
242 --tpl_open;
243 else if (c == '<' && sig[pos+1] != '<')
244 ++tpl_open;
245
246 // collect type name up to ',' or end ')'
247 else if (tpl_open == 0 && c == ',') {
248 // found the extend of the scope ... done
249 result.push_back(sig.substr(start, pos-start));
250 start = pos+1;
251 }
252 }
253
254// add last type
255 result.push_back(sig.substr(start, sig.rfind(")")-start));
256
257 return result;
258}
259
260//----------------------------------------------------------------------------
262{
263// Extract the array size from a given type name (assumes 1D arrays)
264 std::string cleanName = remove_const(name);
265 if (cleanName[cleanName.size()-1] == ']') {
266 std::string::size_type idx = cleanName.rfind('[');
267 if (idx != std::string::npos) {
268 const std::string asize = cleanName.substr(idx+1, cleanName.size()-2);
269 return strtoul(asize.c_str(), nullptr, 0);
270 }
271 }
272
273 return -1;
274}
#define c(i)
Definition RSha256.hxx:101
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
char name[80]
Definition TGX11.cxx:110
static void rstrip(std::string &name)
Definition TypeManip.cxx:66
static std::string::size_type find_qualifier_index(const std::string &name)
Definition TypeManip.cxx:18
static void erase_const(std::string &name)
Definition TypeManip.cxx:40
static bool is_varchar(char c)
Definition TypeManip.cxx:13
std::string remove_const(const std::string &cppname)
Definition TypeManip.cxx:80
void cppscope_to_legalname(std::string &cppscope)
std::string template_base(const std::string &cppname)
void cppscope_to_pyscope(std::string &cppscope)
Py_ssize_t array_size(const std::string &name)
std::string clean_type(const std::string &cppname, bool template_strip=true, bool const_strip=true)
std::string compound(const std::string &name)
std::string extract_namespace(const std::string &name)
std::vector< std::string > extract_arg_types(const std::string &sig)