miqt: pass all miqt_string by value, not by pointer

This commit is contained in:
mappu 2024-10-19 10:57:05 +13:00
parent ba92217b67
commit 434c45273a
6 changed files with 33 additions and 49 deletions

View File

@ -9,7 +9,7 @@ import (
func (p CppParameter) RenderTypeCabi() string {
if p.ParameterType == "QString" {
return "struct miqt_string*"
return "struct miqt_string"
} else if _, ok := p.QListOf(); ok {
return "struct miqt_array*"
@ -146,7 +146,7 @@ func emitParametersCabi(m CppMethod, selfType string) string {
for _, p := range m.Parameters {
if p.ParameterType == "QString" {
tmp = append(tmp, "struct miqt_string* "+p.ParameterName)
tmp = append(tmp, "struct miqt_string "+p.ParameterName)
} else if t, ok := p.QListOf(); ok {
tmp = append(tmp, "struct miqt_array* /* of "+t.RenderTypeCabi()+" */ "+p.ParameterName)
@ -197,9 +197,10 @@ func emitCABI2CppForwarding(p CppParameter, indent string) (preamble string, for
nameprefix := makeNamePrefix(p.ParameterName)
if p.ParameterType == "QString" {
// The CABI has accepted two parameters - need to convert to one real QString
// Create it on the stack
preamble += indent + "QString " + nameprefix + "_QString = QString::fromUtf8(&" + p.ParameterName + "->data, " + p.ParameterName + "->len);\n"
// The CABI received parameter is a struct miqt_string, passed by value
// C++ needs it as a QString. Create one on the stack for automatic cleanup
// The caller will free the miqt_string
preamble += indent + "QString " + nameprefix + "_QString = QString::fromUtf8(" + p.ParameterName + ".data, " + p.ParameterName + ".len);\n"
return preamble, nameprefix + "_QString"
} else if listType, ok := p.QListOf(); ok {
@ -315,7 +316,11 @@ func emitAssignCppToCabi(assignExpression string, p CppParameter, rvalue string)
afterCall += indent + "QByteArray " + namePrefix + "_b = " + namePrefix + "_ret.toUtf8();\n"
}
afterCall += indent + assignExpression + "miqt_strdup(" + namePrefix + "_b.data(), " + namePrefix + "_b.length());\n"
afterCall += indent + "struct miqt_string " + namePrefix + "_ms;\n"
afterCall += indent + namePrefix + "_ms.len = " + namePrefix + "_b.length();\n"
afterCall += indent + namePrefix + "_ms.data = static_cast<char*>(malloc(" + namePrefix + "_ms.len));\n"
afterCall += indent + "memcpy(" + namePrefix + "_ms.data, " + namePrefix + "_b.data(), " + namePrefix + "_ms.len);\n"
afterCall += indent + assignExpression + namePrefix + "_ms;\n"
} else if t, ok := p.QListOf(); ok {

View File

@ -142,7 +142,7 @@ func (p CppParameter) RenderTypeGo(gfs *goFileState) string {
func (p CppParameter) parameterTypeCgo() string {
if p.ParameterType == "QString" {
return "*C.struct_miqt_string"
return "C.struct_miqt_string"
}
if _, ok := p.QListOf(); ok {
@ -256,11 +256,13 @@ func (gfs *goFileState) emitParameterGo2CABIForwarding(p CppParameter) (preamble
// Go: convert string -> miqt_string*
// CABI: convert miqt_string* -> real QString
gfs.imports["libmiqt"] = struct{}{}
preamble += nameprefix + "_ms := libmiqt.Strdupg(" + p.ParameterName + ")\n"
preamble += "defer C.free(" + nameprefix + "_ms)\n"
gfs.imports["unsafe"] = struct{}{}
preamble += nameprefix + "_ms := C.struct_miqt_string{}\n"
preamble += nameprefix + "_ms.data = C.CString(" + p.ParameterName + ")\n"
preamble += nameprefix + "_ms.len = C.size_t(len(" + p.ParameterName + "))\n"
preamble += "defer C.free(unsafe.Pointer(" + nameprefix + "_ms.data))\n"
rvalue = "(*C.struct_miqt_string)(" + nameprefix + "_ms)"
rvalue = nameprefix + "_ms"
} else if listType, ok := p.QListOf(); ok {
// QList<T>
@ -359,9 +361,9 @@ func (gfs *goFileState) emitCabiToGo(assignExpr string, rt CppParameter, rvalue
} else if rt.ParameterType == "QString" {
gfs.imports["unsafe"] = struct{}{}
shouldReturn = "var " + namePrefix + "_ms *C.struct_miqt_string = "
afterword += namePrefix + "_ret := C.GoStringN(&" + namePrefix + "_ms.data, C.int(int64(" + namePrefix + "_ms.len)))\n"
afterword += "C.free(unsafe.Pointer(" + namePrefix + "_ms))\n"
shouldReturn = "var " + namePrefix + "_ms C.struct_miqt_string = "
afterword += namePrefix + "_ret := C.GoStringN(" + namePrefix + "_ms.data, C.int(int64(" + namePrefix + "_ms.len)))\n"
afterword += "C.free(unsafe.Pointer(" + namePrefix + "_ms.data))\n"
afterword += assignExpr + namePrefix + "_ret"
return shouldReturn + " " + rvalue + "\n" + afterword

View File

@ -1,8 +0,0 @@
#include "libmiqt.h"
struct miqt_string* miqt_strdup(const char* src, size_t len) {
struct miqt_string* ret = (struct miqt_string*)( malloc(len + sizeof(size_t)) );
ret->len = len;
memcpy(&ret->data, src, len);
return ret;
}

10
libmiqt/libmiqt.go Normal file
View File

@ -0,0 +1,10 @@
package libmiqt
// SPDX-License-Identifier: MIT
/*
#include "libmiqt.h"
*/
import "C"

View File

@ -10,12 +10,12 @@ extern "C" {
struct miqt_string {
size_t len;
char data; // Data continues after this element, all in the same allocation
char* data;
};
struct miqt_array {
size_t len;
void* data; // Separate, second allocation
void* data;
};
struct miqt_string* miqt_strdup(const char* src, size_t len);

View File

@ -1,25 +0,0 @@
package libmiqt
// SPDX-License-Identifier: MIT
/*
#include "libmiqt.h"
struct miqt_string* miqt_strdupg(_GoString_ gs) {
return miqt_strdup(_GoStringPtr(gs), _GoStringLen(gs));
}
*/
import "C"
import (
"unsafe"
)
// Strdupg will strdup a Go string into a miqt_string*.
// It is typed as returning an unsafe.Pointer because Cgo types cannot be shared
// across Go file boundaries.
func Strdupg(s string) unsafe.Pointer {
return unsafe.Pointer(C.miqt_strdupg(s))
}