Streamline and improve std::string typemaps

Avoid unnecessary heap allocations, just use temporary variables.

Actually update the string parameters passed by pointer/non-const
reference. This requires the pointers passed to actually be non-const,
so update the C-specific unit test runme to use a char buffer instead of
a literal string.

Also simplify the code copying the string contents to just use strdup()
(if there are ever any platforms where this POSIX functions is not
available, we could just define it ourselves once instead of using
strlen() + malloc() + memcpy() manually twice).
This commit is contained in:
Vadim Zeitlin 2021-12-05 03:05:30 +01:00
commit aacc930023
2 changed files with 49 additions and 38 deletions

View file

@ -6,7 +6,8 @@
int main()
{
char *myComposedString = c_backend_cpp_natural_std_string_myStringAppend("World, ", "Hello!");
char buf[] = "World, ";
char *myComposedString = c_backend_cpp_natural_std_string_myStringAppend(buf, "Hello!");
assert(myComposedString);
assert(strcmp(myComposedString, "World, Hello!") == 0);

View file

@ -2,6 +2,31 @@
#include <string>
%}
%fragment("SwigStrInOut", "header") {
class SwigStrInOut {
std::string str_;
char* ptr_;
size_t len_;
public:
void init(char* ptr) {
ptr_ = ptr;
if (ptr_) {
str_ = ptr_;
len_ = str_.length();
}
}
std::string* str() { return &str_; }
~SwigStrInOut() {
if (ptr_) {
memcpy(ptr_, str_.c_str(), len_);
ptr_[len_] = '\0';
}
}
};
}
namespace std {
// use "const string &" typemaps for wrapping member strings
@ -9,49 +34,34 @@ namespace std {
class string;
%typemap(ctype) string "char *"
%typemap(ctype) string, const string & "const char *"
%typemap(ctype) string * "char *"
%typemap(ctype) string & "char *"
%typemap(ctype) const string & "char *"
%typemap(in) string {
if ($input) {
$1.assign($input);
}
else {
$1.resize(0);
}
}
%typemap(in) string %{
if ($input)
$1 = $input;
%}
%typemap(in) const string &, string *, string & {
if ($input) {
$1 = new std::string($input);
}
else {
$1 = new std::string();
$1->resize(0);
}
}
%typemap(in) const string & (std::string temp) %{
if ($input)
temp = $input;
$1 = &temp;
%}
%typemap(freearg) const string &, string *, string & {
if ($1)
delete $1;
}
%typemap(in, fragment="SwigStrInOut") string * (SwigStrInOut temp), string & (SwigStrInOut temp) %{
temp.init($input);
$1 = temp.str();
%}
%typemap(out) string {
const char *str = cppresult.c_str();
size_t len = strlen(str);
$result = (char *) malloc(len + 1);
memcpy($result, str, len);
$result[len] = '\0';
}
// Note that we don't support strings with embedded NULs, as there is no way to
// return their length to C code anyhow.
%typemap(out) string %{
$result = strdup(cppresult.c_str());
%}
%typemap(out) const string &, string *, string & {
const char *str = cppresult->c_str();
size_t len = strlen(str);
$result = (char *) malloc(len + 1);
memcpy($result, str, len);
$result[len] = '\0';
}
%typemap(out) const string &, string *, string & %{
$result = strdup(cppresult->c_str());
%}
}