From 2ccc11f57d3d59e1cba7e11109ee60375b9b5510 Mon Sep 17 00:00:00 2001 From: mappu Date: Thu, 15 Aug 2024 19:50:30 +1200 Subject: [PATCH] genbindings: QStringList handling --- cmd/genbindings/clang2il.go | 6 +++ cmd/genbindings/emitcabi.go | 78 +++++++++++++++++++++++++++---------- cmd/genbindings/emitgo.go | 36 +++++++++++++---- 3 files changed, 92 insertions(+), 28 deletions(-) diff --git a/cmd/genbindings/clang2il.go b/cmd/genbindings/clang2il.go index 1568333..9aac35a 100644 --- a/cmd/genbindings/clang2il.go +++ b/cmd/genbindings/clang2il.go @@ -398,6 +398,12 @@ func parseSingleTypeString(p string) CppParameter { } else if tok == "WId" { // Transform typedef insert.ParameterType += " uintptr_t" + } else if tok == "QStringList" { + insert.ParameterType += " QList" + } else if len(tok) > 4 && strings.HasSuffix(tok, "List") { + // Typedef e.g. QObjectList + // QObjectList is a pointer, but QStringList is a whole custom class + insert.ParameterType += " QList<" + tok[0:len(tok)-4] + " *>" } else { // Valid part of the type name insert.ParameterType += " " + tok diff --git a/cmd/genbindings/emitcabi.go b/cmd/genbindings/emitcabi.go index facd97f..22c3a97 100644 --- a/cmd/genbindings/emitcabi.go +++ b/cmd/genbindings/emitcabi.go @@ -74,10 +74,17 @@ func emitParametersCabi(m CppMethod, selfType string) string { tmp = append(tmp, "const char* "+p.ParameterName+", size_t "+p.ParameterName+"_Strlen") } else if t, ok := p.QListOf(); ok { - // The Go code has called this with two arguments: T* and len - // Declare that we take two parameters - // TODO support QList - tmp = append(tmp, t.ParameterType+"* "+p.ParameterName+", size_t "+p.ParameterName+"_len") + + if t.ParameterType == "QString" { + // Combov + tmp = append(tmp, "char** "+p.ParameterName+", int64_t* "+p.ParameterName+"_Lengths, size_t "+p.ParameterName+"_len") + + } else { + // The Go code has called this with two arguments: T* and len + // Declare that we take two parameters + // TODO support QList + tmp = append(tmp, t.ParameterType+"* "+p.ParameterName+", size_t "+p.ParameterName+"_len") + } } else if (p.ByRef || p.Pointer) && p.QtClassType() { // Pointer to Qt type @@ -122,15 +129,31 @@ func emitParametersCABI2CppForwarding(params []CppParameter) (preamble string, f preamble += "\tQString " + p.ParameterName + "_QString = QString::fromUtf8(" + p.ParameterName + ", " + p.ParameterName + "_Strlen);\n" tmp = append(tmp, p.ParameterName+"_QString") - } else if _, ok := p.QListOf(); ok { - // The CABI has accepted two parameters - need to convert to one real QList<> - // Create it on the stack - preamble += "\t" + p.RenderTypeCpp() + " " + p.ParameterName + "_QList;\n" - preamble += "\t" + p.ParameterName + "_QList.reserve(" + p.ParameterName + "_len);\n" - preamble += "\tfor(size_t i = 0; i < " + p.ParameterName + "_len; ++i) {\n" - preamble += "\t\t" + p.ParameterName + "_QList.push_back(" + p.ParameterName + "++);\n" - preamble += "\t}\n" - tmp = append(tmp, p.ParameterName+"_QList") + } else if listType, ok := p.QListOf(); ok { + + if listType.ParameterType == "QString" { + + // Combo (3 parameters) + preamble += "\t" + p.ParameterType + " " + p.ParameterName + "_QList;\n" + preamble += "\t" + p.ParameterName + "_QList.reserve(" + p.ParameterName + "_len);\n" + preamble += "\tfor(size_t i = 0; i < " + p.ParameterName + "_len; ++i) {\n" + preamble += "\t\t" + p.ParameterName + "_QList.push_back(QString::fromUtf8(*" + p.ParameterName + ", *" + p.ParameterName + "_Lengths));\n" + preamble += "\t\t" + p.ParameterName + "++;\n" + preamble += "\t\t" + p.ParameterName + "_Lengths++;\n" + preamble += "\t}\n" + tmp = append(tmp, p.ParameterName+"_QList") + + } else { + + // The CABI has accepted two parameters - need to convert to one real QList<> + // Create it on the stack + preamble += "\t" + p.ParameterType + " " + p.ParameterName + "_QList;\n" + preamble += "\t" + p.ParameterName + "_QList.reserve(" + p.ParameterName + "_len);\n" + preamble += "\tfor(size_t i = 0; i < " + p.ParameterName + "_len; ++i) {\n" + preamble += "\t\t" + p.ParameterName + "_QList.push_back(" + p.ParameterName + "++);\n" + preamble += "\t}\n" + tmp = append(tmp, p.ParameterName+"_QList") + } } else if p.IntType() { // Use the raw ParameterType to select an explicit integer overload @@ -350,13 +373,28 @@ func emitBindingCpp(src *CppParsedHeader, filename string) (string, error) { afterCall += "\t*_out_Strlen = b.length();\n" } else if t, ok := m.ReturnType.QListOf(); ok { - shouldReturn = m.ReturnType.ParameterType + " ret = " - afterCall += "\t// Convert QList<> from C++ memory to manually-managed C memory\n" - afterCall += "\t*_out = static_cast<" + t.RenderTypeCpp() + ">(malloc(sizeof(" + t.RenderTypeCpp() + ") * ret.length()));\n" - afterCall += "\tfor (int i = 0, e = ret.length(); i < e; ++i) {\n" - afterCall += "\t\t_out[i] = ret[i];\n" - afterCall += "\t}\n" - afterCall += "\t*_out_len = ret.length();\n" + + if !t.QtClassType() || (t.QtClassType() && t.Pointer) { // QList, QList + + shouldReturn = m.ReturnType.ParameterType + " ret = " + afterCall += "\t// Convert QList<> from C++ memory to manually-managed C memory\n" + afterCall += "\t*_out = static_cast<" + t.RenderTypeCpp() + ">(malloc(sizeof(" + t.RenderTypeCpp() + ") * ret.length()));\n" + afterCall += "\tfor (int i = 0, e = ret.length(); i < e; ++i) {\n" + afterCall += "\t\t_out[i] = ret[i];\n" + afterCall += "\t}\n" + afterCall += "\t*_out_len = ret.length();\n" + + } else { // QList + + shouldReturn = m.ReturnType.ParameterType + " ret = " + afterCall += "\t// Convert QList<> from C++ memory to manually-managed C memory of copy-constructed pointers\n" + afterCall += "\t*_out = static_cast<" + t.RenderTypeCpp() + "*>(malloc(sizeof(" + t.RenderTypeCpp() + "*) * ret.length()));\n" + afterCall += "\tfor (int i = 0, e = ret.length(); i < e; ++i) {\n" + afterCall += "\t\t_out[i] = new " + t.ParameterType + "(ret[i]);\n" + afterCall += "\t}\n" + afterCall += "\t*_out_len = ret.length();\n" + + } } else if m.ReturnType.QtClassType() && !m.ReturnType.Pointer { shouldReturn = m.ReturnType.ParameterType + " ret = " diff --git a/cmd/genbindings/emitgo.go b/cmd/genbindings/emitgo.go index 7b4e9ea..1a35e65 100644 --- a/cmd/genbindings/emitgo.go +++ b/cmd/genbindings/emitgo.go @@ -106,16 +106,36 @@ func emitParametersGo2CABIForwarding(m CppMethod) (preamble string, fowarding st // Go: convert T[] -> t* and len // CABI: create a real QList<> - // TODO handle QList + if listType.ParameterType == "QString" { + // Combo - preamble += "// For the C ABI, malloc a C array of raw pointers\n" - preamble += p.ParameterName + "_CArray := (*[0xffff]*C." + listType.ParameterType + ")(C.malloc(c.ulong(8 * len(" + p.ParameterName + "))))\n" - preamble += "defer C.free(" + p.ParameterName + "_CArray)\n" - preamble += "for i := range " + p.ParameterName + "{\n" - preamble += p.ParameterName + "_CArray[i] = " + p.ParameterName + "[i].cPointer()\n" - preamble += "}\n" + preamble += "// For the C ABI, malloc two C arrays; raw char* pointers and their lengths\n" + preamble += p.ParameterName + "_CArray := (*[0xffff]*C." + listType.ParameterType + ")(C.malloc(c.ulong(8 * len(" + p.ParameterName + "))))\n" + preamble += p.ParameterName + "_Lengths := (*[0xffff]*C." + listType.ParameterType + ")(C.malloc(c.ulong(8 * len(" + p.ParameterName + "))))\n" + preamble += "defer C.free(" + p.ParameterName + "_CArray)\n" + preamble += "defer C.free(" + p.ParameterName + "_Lengths)\n" + preamble += "for i := range " + p.ParameterName + "{\n" + preamble += "single_cstring := C.CString(" + p.ParameterName + "[i])\n" + preamble += "defer C.free(single_cstring)\n" + preamble += p.ParameterName + "_CArray[i] = single_cstring\n" + preamble += p.ParameterName + "__Lengths[i] = len(" + p.ParameterName + "[i])\n" + preamble += "}\n" - tmp = append(tmp, p.ParameterName+"_CArray, len("+p.ParameterName+")") + tmp = append(tmp, p.ParameterName+"_CArray, "+p.ParameterName+"_Lengths, len("+p.ParameterName+")") + + } else { + + // TODO handle QList + + preamble += "// For the C ABI, malloc a C array of raw pointers\n" + preamble += p.ParameterName + "_CArray := (*[0xffff]*C." + listType.ParameterType + ")(C.malloc(c.ulong(8 * len(" + p.ParameterName + "))))\n" + preamble += "defer C.free(" + p.ParameterName + "_CArray)\n" + preamble += "for i := range " + p.ParameterName + "{\n" + preamble += p.ParameterName + "_CArray[i] = " + p.ParameterName + "[i].cPointer()\n" + preamble += "}\n" + + tmp = append(tmp, p.ParameterName+"_CArray, len("+p.ParameterName+")") + } } else if p.Pointer && p.ParameterType == "char" { // Single char* argument