Add cxx{in,out}type typemaps and use them for std::string
This makes using returning strings much simpler to use from C++ code as the returned pointers don't have to be deleted manually -- although, of course, this does require an extra allocation and copy and so should be avoided for the very long strings. Add a new runtime test showing how simple and convenient it is to use the functions working with string using the C++ wrappers now.
This commit is contained in:
parent
8b871b10fe
commit
fd11a591a3
5 changed files with 135 additions and 30 deletions
|
|
@ -476,6 +476,26 @@ area: 7.068583
|
|||
<td>Type of the result variable used for the return value if the wrapped function is a C++ function
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>cxxintype</tt></td>
|
||||
<td>Defines the type for the parameters of C++ wrapper functions corresponding to this type. By default is the same as <tt>ctype</tt>, but may sometimes be different to make the functions more convenient to use. For example, <tt>ctype</tt> for <tt>std::string</tt> is <tt>const char*</tt>, but <tt>cxxintype</tt> typemap for it is <tt>std::string const&</tt>, i.e. even though the C++ string passed as a raw pointer via C API, the C++ wrapper still accepts a C++ string. If this typemap is defined, <tt>cxxin</tt> should normally be defined as well. If it is not defined, <tt>ctype</tt> is used.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>cxxouttype</tt></td>
|
||||
<td>Similar to <tt>cxxintype</tt>, but is used for the function return values and together with <tt>cxxout</tt> typemap. Also defaults to <tt>ctype</tt> if not defined.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>cxxin</tt></td>
|
||||
<td>Defines how to transform <tt>cxxintype</tt> value to <tt>ctype</tt>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>cxxout</tt></td>
|
||||
<td>Defines how to transform <tt>ctype</tt> value returned by a function to <tt>cxxouttype</tt>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<H3>C Typemaps, a Code Generation Walkthrough</H3>
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@
|
|||
int main(int argc, const char *argv[]) {
|
||||
{
|
||||
li_boost_shared_ptr::Klass k("me oh my");
|
||||
assert( strcmp(k.getValue(), "me oh my") == 0 );
|
||||
assert( k.getValue() == "me oh my" );
|
||||
}
|
||||
|
||||
{
|
||||
li_boost_shared_ptr::Klass k{li_boost_shared_ptr_factorycreate()};
|
||||
assert( strcmp(k.getValue(), "factorycreate") == 0 );
|
||||
assert( k.getValue() == "factorycreate" );
|
||||
}
|
||||
}
|
||||
|
|
|
|||
26
Examples/test-suite/c/li_std_string_runme.cxx
Normal file
26
Examples/test-suite/c/li_std_string_runme.cxx
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#include "li_std_string_wrap.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
using namespace li_std_string;
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
Structure st;
|
||||
assert( st.MemberString().empty() );
|
||||
|
||||
st.MemberString("bloordyblop");
|
||||
assert( st.MemberString() == "bloordyblop" );
|
||||
|
||||
assert( st.MemberString2() == "member string 2" );
|
||||
|
||||
assert( st.ConstMemberString() == "const member string" );
|
||||
|
||||
st.StaticMemberString(std::string("static bloordyblop"));
|
||||
assert( st.StaticMemberString() == "static bloordyblop" );
|
||||
|
||||
assert( Structure::StaticMemberString2() == "static member string 2" );
|
||||
assert( Structure::ConstStaticMemberString() == "const static member string" );
|
||||
|
||||
Foo f;
|
||||
assert( f.test("1+") == "1+1" );
|
||||
}
|
||||
|
|
@ -27,6 +27,10 @@ public:
|
|||
};
|
||||
}
|
||||
|
||||
%fragment("include_string", "cxxheader") %{
|
||||
#include <string>
|
||||
%}
|
||||
|
||||
namespace std {
|
||||
|
||||
// use "const string &" typemaps for wrapping member strings
|
||||
|
|
@ -68,4 +72,19 @@ class string;
|
|||
// taking strings and raw pointers in the generated wrappers.
|
||||
%typemap(typecheck) string, const string &, string *, string & = char *;
|
||||
|
||||
|
||||
// Define typemaps for wrapping strings back into std::string in C++ wrappers
|
||||
// and accepting strings directly.
|
||||
|
||||
%typemap(cxxintype, fragment="include_string") string, const string & "std::string const&"
|
||||
|
||||
%typemap(cxxin) string, const string & "$1.c_str()"
|
||||
|
||||
%typemap(cxxouttype, fragment="include_string") string, const string & "std::string"
|
||||
|
||||
%typemap(cxxout, noblock="1") string, const string & %{
|
||||
$result = std::string($cresult);
|
||||
free(const_cast<char*>($cresult));
|
||||
%}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -611,35 +611,49 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
for (; p; p = nextSibling(p)) {
|
||||
// Static variables use fully qualified names, so we can't just use the name directly.
|
||||
scoped_dohptr name_ptr;
|
||||
String* name = Getattr(p, "name");
|
||||
if (!name) {
|
||||
// Parameters can also not have any names at all, in which case we use auto-generated one.
|
||||
name = Getattr(p, "lname");
|
||||
} else if (Strstr(name, "::")) {
|
||||
name_ptr = Swig_scopename_last(name);
|
||||
name = name_ptr.get();
|
||||
if (p) {
|
||||
// We want to use readable parameter names in our wrappers instead of the autogenerated arg$N if possible, so do it, and do it before calling
|
||||
// Swig_typemap_attach_parms(), as this uses the parameter names for typemap expansion.
|
||||
for (Parm* p2 = p; p2; p2 = nextSibling(p2)) {
|
||||
String* name = Getattr(p, "name");
|
||||
if (!name) {
|
||||
// Can't do anything for unnamed parameters.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Static variables use fully qualified names, so we need to strip the scope from them.
|
||||
scoped_dohptr name_ptr;
|
||||
if (Strstr(name, "::")) {
|
||||
name_ptr = Swig_scopename_last(name);
|
||||
name = name_ptr.get();
|
||||
}
|
||||
|
||||
Setattr(p, "lname", name);
|
||||
}
|
||||
|
||||
const type_desc ptype_desc = lookup_cxx_parm_type(n, p);
|
||||
if (!ptype_desc.type()) {
|
||||
Swig_warning(WARN_C_TYPEMAP_CTYPE_UNDEF, Getfile(p), Getline(p),
|
||||
"No ctype typemap defined for the parameter \"%s\" of %s\n",
|
||||
name,
|
||||
Getattr(n, "sym:name")
|
||||
);
|
||||
return;
|
||||
Swig_typemap_attach_parms("cxxin", p, NULL);
|
||||
|
||||
for (; p; p = nextSibling(p)) {
|
||||
String* const name = Getattr(p, "lname");
|
||||
|
||||
const cxx_ptype_desc ptype_desc = lookup_cxx_parm_type(n, p);
|
||||
if (!ptype_desc.type()) {
|
||||
Swig_warning(WARN_C_TYPEMAP_CTYPE_UNDEF, Getfile(p), Getline(p),
|
||||
"No ctype typemap defined for the parameter \"%s\" of %s\n",
|
||||
name,
|
||||
Getattr(n, "sym:name")
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Len(parms_cxx))
|
||||
Append(parms_cxx, ", ");
|
||||
Printv(parms_cxx, ptype_desc.type(), " ", name, NIL);
|
||||
|
||||
if (Len(parms_call))
|
||||
Append(parms_call, ", ");
|
||||
Append(parms_call, ptype_desc.get_param_code(name));
|
||||
}
|
||||
|
||||
if (Len(parms_cxx))
|
||||
Append(parms_cxx, ", ");
|
||||
Printv(parms_cxx, ptype_desc.type(), " ", name, NIL);
|
||||
|
||||
if (Len(parms_call))
|
||||
Append(parms_call, ", ");
|
||||
Append(parms_call, ptype_desc.get_param_code(name));
|
||||
}
|
||||
|
||||
// Avoid checking for exceptions unnecessarily. Note that this is more than an optimization: we'd get into infinite recursion if we checked for exceptions
|
||||
|
|
@ -1006,6 +1020,9 @@ private:
|
|||
// The logic here is somewhat messy because we use the same "$resolved_type*" typemap for pointers/references to both enums and classes, but we actually
|
||||
// need to do quite different things for them. It could probably be simplified by changing the typemaps to be distinct, but this would require also updating
|
||||
// the code for C wrappers generation in substituteResolvedTypeSpecialVariable().
|
||||
//
|
||||
// An even better idea might be to try to define this using cxx{in,out} typemaps for the various types and let the generic SWIG machinery do all the
|
||||
// matching instead of doing it in the code here.
|
||||
scoped_dohptr resolved_type(SwigType_typedef_resolve_all(type));
|
||||
scoped_dohptr base_resolved_type(SwigType_base(resolved_type));
|
||||
|
||||
|
|
@ -1182,11 +1199,23 @@ private:
|
|||
// Ensure our own replaceSpecialVariables() is used for $typemap() expansion.
|
||||
temp_ptr_setter<cxx_ptype_desc*> set(&ptype_desc_, &ptype_desc);
|
||||
|
||||
if (String* type = Swig_typemap_lookup("ctype", p, "", NULL)) {
|
||||
bool use_cxxin = true;
|
||||
String* type = Swig_typemap_lookup("cxxintype", p, "", NULL);
|
||||
if (!type) {
|
||||
use_cxxin = false;
|
||||
type = Swig_typemap_lookup("ctype", p, "", NULL);
|
||||
}
|
||||
|
||||
if (type) {
|
||||
ptype_desc.set_type(type);
|
||||
do_resolve_type(n, Getattr(p, "type"), ptype_desc.type(), &ptype_desc, NULL);
|
||||
}
|
||||
|
||||
if (use_cxxin) {
|
||||
if (String* in_tm = Getattr(p, "tmap:cxxin"))
|
||||
ptype_desc.apply_in_typemap(Copy(in_tm));
|
||||
}
|
||||
|
||||
return ptype_desc;
|
||||
}
|
||||
|
||||
|
|
@ -1194,13 +1223,24 @@ private:
|
|||
// As above, ensure our replaceSpecialVariables() is used.
|
||||
temp_ptr_setter<cxx_rtype_desc*> set(&rtype_desc_, &rtype_desc);
|
||||
|
||||
String* type = Swig_typemap_lookup("ctype", n, "", NULL);
|
||||
bool use_cxxout = true;
|
||||
String* type(Swig_typemap_lookup("cxxouttype", n, "", NULL));
|
||||
if (!type) {
|
||||
use_cxxout = false;
|
||||
type = Swig_typemap_lookup("ctype", n, "", NULL);
|
||||
}
|
||||
|
||||
if (!type)
|
||||
return false;
|
||||
|
||||
rtype_desc.set_type(type);
|
||||
do_resolve_type(n, Getattr(n, "type"), rtype_desc.type(), NULL, &rtype_desc);
|
||||
|
||||
if (use_cxxout) {
|
||||
if (String* out_tm = Swig_typemap_lookup("cxxout", n, "", NULL))
|
||||
rtype_desc.apply_out_typemap(out_tm);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue