mirror of
https://github.com/mappu/miqt.git
synced 2024-12-22 00:48:38 +00:00
genbindings: add qmap/qhash support
This commit is contained in:
parent
69011a5acb
commit
a009008525
@ -82,6 +82,8 @@ func AllowHeader(fullpath string) bool {
|
||||
"qbytearray.h", // QByteArray does not exist in this binding
|
||||
"qlist.h", // QList does not exist in this binding
|
||||
"qvector.h", // QVector does not exist in this binding
|
||||
"qhash.h", // QHash does not exist in this binding
|
||||
"qmap.h", // QMap does not exist in this binding
|
||||
"qtcoreexports.h", // Nothing bindable here and has Q_CORE_EXPORT definition issues
|
||||
"q20algorithm.h", // Qt 6 unstable header
|
||||
"q20functional.h", // Qt 6 unstable header
|
||||
@ -216,9 +218,6 @@ func AllowMethod(className string, mm CppMethod) error {
|
||||
// Any type not permitted by AllowClass is also not permitted by this method.
|
||||
func AllowType(p CppParameter, isReturnType bool) error {
|
||||
|
||||
if p.QMapOf() {
|
||||
return ErrTooComplex // Example???
|
||||
}
|
||||
if p.QPairOf() {
|
||||
return ErrTooComplex // e.g. QGradientStop
|
||||
}
|
||||
@ -238,6 +237,15 @@ func AllowType(p CppParameter, isReturnType bool) error {
|
||||
return ErrTooComplex
|
||||
}
|
||||
}
|
||||
if kType, vType, ok := p.QMapOf(); ok {
|
||||
if err := AllowType(kType, isReturnType); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := AllowType(vType, isReturnType); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if !AllowClass(p.ParameterType) {
|
||||
return ErrTooComplex // This whole class type has been blocked, not only as a parameter/return type
|
||||
}
|
||||
@ -294,6 +302,12 @@ func AllowType(p CppParameter, isReturnType bool) error {
|
||||
if strings.Contains(p.ParameterType, `Iterator::value_type`) {
|
||||
return ErrTooComplex // e.g. qcbormap
|
||||
}
|
||||
if strings.Contains(p.ParameterType, `>::iterator`) ||
|
||||
strings.Contains(p.ParameterType, `>::const_iterator`) {
|
||||
// qresultstore.h tries to create a
|
||||
// NewQtPrivate__ResultIteratorBase2(_mapIterator QMap<int, ResultItem>__const_iterator)
|
||||
return ErrTooComplex
|
||||
}
|
||||
if strings.Contains(p.ParameterType, `::QPrivate`) {
|
||||
return ErrTooComplex // e.g. QAbstractItemModel::QPrivateSignal
|
||||
}
|
||||
|
@ -20,6 +20,9 @@ func (p CppParameter) RenderTypeCabi() string {
|
||||
} else if _, ok := p.QSetOf(); ok {
|
||||
return "struct miqt_array"
|
||||
|
||||
} else if _, _, ok := p.QMapOf(); ok {
|
||||
return "struct miqt_map"
|
||||
|
||||
} else if (p.Pointer || p.ByRef) && p.QtClassType() {
|
||||
return cabiClassName(p.ParameterType) + "*"
|
||||
|
||||
@ -231,6 +234,32 @@ func emitCABI2CppForwarding(p CppParameter, indent string) (preamble string, for
|
||||
preamble += indent + "}\n"
|
||||
return preamble, nameprefix + "_QList"
|
||||
|
||||
} else if kType, vType, ok := p.QMapOf(); ok {
|
||||
preamble += indent + p.GetQtCppType().ParameterType + " " + nameprefix + "_QMap;\n"
|
||||
|
||||
// This container may be a QMap or a QHash
|
||||
// QHash supports .reserve(), but QMap doesn't
|
||||
if strings.HasPrefix(p.ParameterType, "QHash<") {
|
||||
preamble += indent + nameprefix + "_QMap.reserve(" + p.ParameterName + ".len);\n"
|
||||
}
|
||||
|
||||
preamble += indent + kType.RenderTypeCabi() + "* " + nameprefix + "_karr = static_cast<" + kType.RenderTypeCabi() + "*>(" + p.ParameterName + ".keys);\n"
|
||||
preamble += indent + vType.RenderTypeCabi() + "* " + nameprefix + "_varr = static_cast<" + vType.RenderTypeCabi() + "*>(" + p.ParameterName + ".values);\n"
|
||||
preamble += indent + "for(size_t i = 0; i < " + p.ParameterName + ".len; ++i) {\n"
|
||||
|
||||
kType.ParameterName = nameprefix + "_karr[i]"
|
||||
addPreK, addFwdK := emitCABI2CppForwarding(kType, indent+"\t")
|
||||
preamble += addPreK
|
||||
|
||||
vType.ParameterName = nameprefix + "_varr[i]"
|
||||
addPreV, addFwdV := emitCABI2CppForwarding(vType, indent+"\t")
|
||||
preamble += addPreV
|
||||
|
||||
preamble += indent + "\t" + nameprefix + "_QMap[" + addFwdK + "] = " + addFwdV + ";\n"
|
||||
|
||||
preamble += indent + "}\n"
|
||||
return preamble, nameprefix + "_QMap"
|
||||
|
||||
} else if p.IsFlagType() || p.IntType() || p.IsKnownEnum() {
|
||||
castSrc := p.ParameterName
|
||||
castType := p.RenderTypeQtCpp()
|
||||
@ -386,6 +415,30 @@ func emitAssignCppToCabi(assignExpression string, p CppParameter, rvalue string)
|
||||
|
||||
afterCall += indent + assignExpression + "" + namePrefix + "_out;\n"
|
||||
|
||||
} else if kType, vType, ok := p.QMapOf(); ok {
|
||||
// QMap<K,V>
|
||||
|
||||
shouldReturn = p.RenderTypeQtCpp() + " " + namePrefix + "_ret = "
|
||||
|
||||
afterCall += indent + "// Convert QMap<> from C++ memory to manually-managed C memory\n"
|
||||
afterCall += indent + "" + kType.RenderTypeCabi() + "* " + namePrefix + "_karr = static_cast<" + kType.RenderTypeCabi() + "*>(malloc(sizeof(" + kType.RenderTypeCabi() + ") * " + namePrefix + "_ret.size()));\n"
|
||||
afterCall += indent + "" + vType.RenderTypeCabi() + "* " + namePrefix + "_varr = static_cast<" + vType.RenderTypeCabi() + "*>(malloc(sizeof(" + vType.RenderTypeCabi() + ") * " + namePrefix + "_ret.size()));\n"
|
||||
|
||||
afterCall += indent + "int " + namePrefix + "_ctr = 0;\n"
|
||||
afterCall += indent + "for (auto " + namePrefix + "_itr = " + namePrefix + "_ret.keyValueBegin(); " + namePrefix + "_itr != " + namePrefix + "_ret.keyValueEnd(); ++" + namePrefix + "_itr) {\n"
|
||||
afterCall += emitAssignCppToCabi(indent+"\t"+namePrefix+"_karr["+namePrefix+"_ctr] = ", kType, namePrefix+"_itr->first")
|
||||
afterCall += emitAssignCppToCabi(indent+"\t"+namePrefix+"_varr["+namePrefix+"_ctr] = ", vType, namePrefix+"_itr->second")
|
||||
afterCall += indent + "\t" + namePrefix + "_ctr++;\n"
|
||||
|
||||
afterCall += indent + "}\n"
|
||||
|
||||
afterCall += indent + "struct miqt_map " + namePrefix + "_out;\n"
|
||||
afterCall += indent + "" + namePrefix + "_out.len = " + namePrefix + "_ret.size();\n"
|
||||
afterCall += indent + "" + namePrefix + "_out.keys = static_cast<void*>(" + namePrefix + "_karr);\n"
|
||||
afterCall += indent + "" + namePrefix + "_out.values = static_cast<void*>(" + namePrefix + "_varr);\n"
|
||||
|
||||
afterCall += indent + assignExpression + "" + namePrefix + "_out;\n"
|
||||
|
||||
} else if p.QtClassType() && p.ByRef {
|
||||
// It's a pointer in disguise, just needs one cast
|
||||
shouldReturn = p.RenderTypeQtCpp() + " " + namePrefix + "_ret = "
|
||||
@ -439,6 +492,15 @@ func getReferencedTypes(src *CppParsedHeader) []string {
|
||||
foundTypes[t.ParameterType] = struct{}{}
|
||||
}
|
||||
}
|
||||
if kType, vType, ok := p.QMapOf(); ok {
|
||||
foundTypes["QMap"] = struct{}{} // FIXME or QHash?
|
||||
if kType.QtClassType() {
|
||||
foundTypes[kType.ParameterType] = struct{}{}
|
||||
}
|
||||
if vType.QtClassType() {
|
||||
foundTypes[vType.ParameterType] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, c := range src.Classes {
|
||||
@ -490,6 +552,15 @@ func cabiClassName(className string) string {
|
||||
return strings.Replace(className, `::`, `__`, -1)
|
||||
}
|
||||
|
||||
func cabiPreventStructDeclaration(className string) bool {
|
||||
switch className {
|
||||
case "QList", "QString", "QSet", "QMap", "QHash":
|
||||
return true // These types are reprojected
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func emitBindingHeader(src *CppParsedHeader, filename string, packageName string) (string, error) {
|
||||
ret := strings.Builder{}
|
||||
|
||||
@ -523,7 +594,7 @@ extern "C" {
|
||||
ret.WriteString("#ifdef __cplusplus\n")
|
||||
|
||||
for _, ft := range foundTypesList {
|
||||
if ft == "QList" || ft == "QString" { // These types are reprojected
|
||||
if cabiPreventStructDeclaration(ft) {
|
||||
continue
|
||||
}
|
||||
|
||||
@ -545,7 +616,7 @@ extern "C" {
|
||||
ret.WriteString("#else\n")
|
||||
|
||||
for _, ft := range foundTypesList {
|
||||
if ft == "QList" || ft == "QString" { // These types are reprojected
|
||||
if cabiPreventStructDeclaration(ft) {
|
||||
continue
|
||||
}
|
||||
ret.WriteString(`typedef struct ` + cabiClassName(ft) + " " + cabiClassName(ft) + ";\n")
|
||||
|
@ -39,6 +39,10 @@ func (p CppParameter) RenderTypeGo(gfs *goFileState) string {
|
||||
return "map[" + t.RenderTypeGo(gfs) + "]struct{}"
|
||||
}
|
||||
|
||||
if t1, t2, ok := p.QMapOf(); ok {
|
||||
return "map[" + t1.RenderTypeGo(gfs) + "]" + t2.RenderTypeGo(gfs)
|
||||
}
|
||||
|
||||
if p.ParameterType == "void" && p.Pointer {
|
||||
return "unsafe.Pointer"
|
||||
}
|
||||
@ -161,6 +165,10 @@ func (p CppParameter) parameterTypeCgo() string {
|
||||
return "C.struct_miqt_array"
|
||||
}
|
||||
|
||||
if _, _, ok := p.QMapOf(); ok {
|
||||
return "C.struct_miqt_map"
|
||||
}
|
||||
|
||||
tmp := strings.Replace(p.RenderTypeCabi(), `*`, "", -1)
|
||||
|
||||
if strings.HasPrefix(tmp, "const ") && tmp != "const char" { // Special typedef to make this work for const char* signal parameters
|
||||
@ -320,6 +328,39 @@ func (gfs *goFileState) emitParameterGo2CABIForwarding(p CppParameter) (preamble
|
||||
} else if _, ok := p.QSetOf(); ok {
|
||||
panic("QSet<> arguments are not yet implemented") // n.b. doesn't seem to exist in QtCore/QtGui/QtWidgets at all
|
||||
|
||||
} else if kType, vType, ok := p.QMapOf(); ok {
|
||||
// QMap<T>
|
||||
|
||||
gfs.imports["unsafe"] = struct{}{}
|
||||
|
||||
preamble += nameprefix + "_Keys_CArray := (*[0xffff]" + kType.parameterTypeCgo() + ")(C.malloc(C.size_t(" + kType.mallocSizeCgoExpression() + " * len(" + p.ParameterName + "))))\n"
|
||||
preamble += "defer C.free(unsafe.Pointer(" + nameprefix + "_Keys_CArray))\n"
|
||||
|
||||
preamble += nameprefix + "_Values_CArray := (*[0xffff]" + vType.parameterTypeCgo() + ")(C.malloc(C.size_t(" + vType.mallocSizeCgoExpression() + " * len(" + p.ParameterName + "))))\n"
|
||||
preamble += "defer C.free(unsafe.Pointer(" + nameprefix + "_Values_CArray))\n"
|
||||
|
||||
preamble += nameprefix + "_ctr := 0\n"
|
||||
|
||||
preamble += "for " + nameprefix + "_k, " + nameprefix + "_v := range " + p.ParameterName + "{\n"
|
||||
|
||||
kType.ParameterName = nameprefix + "_k"
|
||||
addPreamble, innerRvalue := gfs.emitParameterGo2CABIForwarding(kType)
|
||||
preamble += addPreamble
|
||||
preamble += nameprefix + "_Keys_CArray[" + nameprefix + "_ctr] = " + innerRvalue + "\n"
|
||||
|
||||
vType.ParameterName = nameprefix + "_v"
|
||||
addPreamble, innerRvalue = gfs.emitParameterGo2CABIForwarding(vType)
|
||||
preamble += addPreamble
|
||||
preamble += nameprefix + "_Values_CArray[" + nameprefix + "_ctr] = " + innerRvalue + "\n"
|
||||
|
||||
preamble += nameprefix + "_ctr++\n"
|
||||
|
||||
preamble += "}\n"
|
||||
|
||||
preamble += p.ParameterName + "_mm := C.struct_miqt_map{\nlen: C.size_t(len(" + p.ParameterName + ")),\nkeys: unsafe.Pointer(" + nameprefix + "_Keys_CArray),\nvalues: unsafe.Pointer(" + nameprefix + "_Values_CArray),\n}\n"
|
||||
|
||||
rvalue = p.ParameterName + "_mm"
|
||||
|
||||
} else if p.Pointer && p.ParameterType == "char" {
|
||||
// Single char* argument
|
||||
gfs.imports["unsafe"] = struct{}{}
|
||||
@ -420,6 +461,7 @@ func (gfs *goFileState) emitCabiToGo(assignExpr string, rt CppParameter, rvalue
|
||||
afterword += gfs.emitCabiToGo(namePrefix+"_ret[i] = ", t, namePrefix+"_outCast[i]")
|
||||
|
||||
afterword += "}\n"
|
||||
|
||||
afterword += assignExpr + " " + namePrefix + "_ret\n"
|
||||
return shouldReturn + " " + rvalue + "\n" + afterword
|
||||
|
||||
@ -440,6 +482,24 @@ func (gfs *goFileState) emitCabiToGo(assignExpr string, rt CppParameter, rvalue
|
||||
afterword += assignExpr + " " + namePrefix + "_ret\n"
|
||||
return shouldReturn + " " + rvalue + "\n" + afterword
|
||||
|
||||
} else if kType, vType, ok := rt.QMapOf(); ok {
|
||||
gfs.imports["unsafe"] = struct{}{}
|
||||
|
||||
shouldReturn = "var " + namePrefix + "_mm C.struct_miqt_map = "
|
||||
|
||||
afterword += namePrefix + "_ret := make(map[" + kType.RenderTypeGo(gfs) + "]" + vType.RenderTypeGo(gfs) + ", int(" + namePrefix + "_mm.len))\n"
|
||||
afterword += namePrefix + "_Keys := (*[0xffff]" + kType.parameterTypeCgo() + ")(unsafe.Pointer(" + namePrefix + "_mm.keys))\n"
|
||||
afterword += namePrefix + "_Values := (*[0xffff]" + vType.parameterTypeCgo() + ")(unsafe.Pointer(" + namePrefix + "_mm.values))\n"
|
||||
afterword += "for i := 0; i < int(" + namePrefix + "_mm.len); i++ {\n"
|
||||
|
||||
afterword += gfs.emitCabiToGo(namePrefix+"_entry_Key := ", kType, namePrefix+"_Keys[i]") + "\n"
|
||||
afterword += gfs.emitCabiToGo(namePrefix+"_entry_Value := ", vType, namePrefix+"_Values[i]") + "\n"
|
||||
afterword += namePrefix + "_ret[" + namePrefix + "_entry_Key] = " + namePrefix + "_entry_Value\n"
|
||||
|
||||
afterword += "}\n"
|
||||
afterword += assignExpr + " " + namePrefix + "_ret\n"
|
||||
return shouldReturn + " " + rvalue + "\n" + afterword
|
||||
|
||||
} else if rt.QtClassType() {
|
||||
// Construct our Go type based on this inner CABI type
|
||||
shouldReturn = "" + namePrefix + "_ret := "
|
||||
|
@ -105,6 +105,9 @@ func (p CppParameter) IsFlagType() bool {
|
||||
|
||||
func (p CppParameter) QtClassType() bool {
|
||||
|
||||
// QtClassType returns false for our customized container types (QList,
|
||||
// QMap, QSet, etc)
|
||||
|
||||
// Maybe if it's an inner class
|
||||
if _, ok := KnownClassnames[p.ParameterType]; ok {
|
||||
return true
|
||||
@ -142,9 +145,36 @@ func (p CppParameter) QListOf() (CppParameter, bool) {
|
||||
return CppParameter{}, false
|
||||
}
|
||||
|
||||
func (p CppParameter) QMapOf() bool {
|
||||
return strings.HasPrefix(p.ParameterType, `QMap<`) ||
|
||||
strings.HasPrefix(p.ParameterType, `QHash<`) // TODO support this
|
||||
func (p CppParameter) QMapOf() (CppParameter, CppParameter, bool) {
|
||||
// n.b. Need to block QMap<k,v>::const_terator
|
||||
|
||||
if strings.HasPrefix(p.ParameterType, `QMap<`) && strings.HasSuffix(p.ParameterType, `>`) {
|
||||
interior := tokenizeMultipleParameters(p.ParameterType[5 : len(p.ParameterType)-1])
|
||||
if len(interior) != 2 {
|
||||
panic("QMap<> has unexpected number of template arguments")
|
||||
}
|
||||
|
||||
first := parseSingleTypeString(interior[0])
|
||||
first.ParameterName = p.ParameterName + "_mapkey"
|
||||
second := parseSingleTypeString(interior[1])
|
||||
second.ParameterName = p.ParameterName + "_mapval"
|
||||
return first, second, true
|
||||
}
|
||||
|
||||
if strings.HasPrefix(p.ParameterType, `QHash<`) && strings.HasSuffix(p.ParameterType, `>`) {
|
||||
interior := tokenizeMultipleParameters(p.ParameterType[6 : len(p.ParameterType)-1])
|
||||
if len(interior) != 2 {
|
||||
panic("QHash<> has unexpected number of template arguments")
|
||||
}
|
||||
|
||||
first := parseSingleTypeString(interior[0])
|
||||
first.ParameterName = p.ParameterName + "_hashkey"
|
||||
second := parseSingleTypeString(interior[1])
|
||||
second.ParameterName = p.ParameterName + "_hashval"
|
||||
return first, second, true
|
||||
}
|
||||
|
||||
return CppParameter{}, CppParameter{}, false
|
||||
}
|
||||
|
||||
func (p CppParameter) QPairOf() bool {
|
||||
|
@ -18,6 +18,12 @@ struct miqt_array {
|
||||
void* data;
|
||||
};
|
||||
|
||||
struct miqt_map {
|
||||
size_t len;
|
||||
void* keys;
|
||||
void* values;
|
||||
};
|
||||
|
||||
struct miqt_string* miqt_strdup(const char* src, size_t len);
|
||||
|
||||
typedef const char const_char;
|
||||
|
Loading…
Reference in New Issue
Block a user