Merge pull request #18801 from alalek:java_improve_nested_classes_namespaces

This commit is contained in:
Alexander Alekhin 2020-11-14 22:55:33 +00:00
commit 71db9d3b57

View File

@ -123,7 +123,8 @@ T_CPP_MODULE = Template(read_contents(os.path.join(SCRIPT_DIR, 'templates/cpp_mo
class GeneralInfo():
def __init__(self, type, decl, namespaces):
self.symbol_id, self.namespace, self.classpath, self.classname, self.name = self.parseName(decl[0], namespaces)
self.symbol_id, self.parent_id, self.namespace, self.classpath, self.classname, self.name = self.parseName(decl[0], namespaces)
self.cname = get_cname(self.symbol_id)
# parse doxygen comments
self.params={}
@ -150,6 +151,9 @@ class GeneralInfo():
returns: (namespace, classpath, classname, name)
'''
name = name[name.find(" ")+1:].strip() # remove struct/class/const prefix
parent = name[:name.rfind('.')].strip()
if len(parent) == 0:
parent = None
spaceName = ""
localName = name # <classes>.<name>
for namespace in sorted(namespaces, key=len, reverse=True):
@ -159,31 +163,44 @@ class GeneralInfo():
break
pieces = localName.split(".")
if len(pieces) > 2: # <class>.<class>.<class>.<name>
return name, spaceName, ".".join(pieces[:-1]), pieces[-2], pieces[-1]
return name, parent, spaceName, ".".join(pieces[:-1]), pieces[-2], pieces[-1]
elif len(pieces) == 2: # <class>.<name>
return name, spaceName, pieces[0], pieces[0], pieces[1]
return name, parent, spaceName, pieces[0], pieces[0], pieces[1]
elif len(pieces) == 1: # <name>
return name, spaceName, "", "", pieces[0]
return name, parent, spaceName, "", "", pieces[0]
else:
return name, spaceName, "", "" # error?!
return name, parent, spaceName, "", "" # error?!
def fullName(self, isCPP=False):
result = ".".join([self.fullClass(), self.name])
return result if not isCPP else get_cname(result)
def fullNameOrigin(self):
result = self.symbol_id
return result
def fullClass(self, isCPP=False):
def fullNameJAVA(self):
result = '.'.join([self.fullParentNameJAVA(), self.jname])
return result
def fullNameCPP(self):
result = self.cname
return result
def fullParentNameJAVA(self):
result = ".".join([f for f in [self.namespace] + self.classpath.split(".") if len(f)>0])
return result if not isCPP else get_cname(result)
return result
def fullParentNameCPP(self):
result = get_cname(self.parent_id)
return result
class ConstInfo(GeneralInfo):
def __init__(self, decl, addedManually=False, namespaces=[], enumType=None):
GeneralInfo.__init__(self, "const", decl, namespaces)
self.cname = get_cname(self.name)
self.value = decl[1]
self.enumType = enumType
self.addedManually = addedManually
if self.namespace in namespaces_dict:
self.name = '%s_%s' % (namespaces_dict[self.namespace], self.name)
prefix = namespaces_dict[self.namespace]
if prefix:
self.name = '%s_%s' % (prefix, self.name)
def __repr__(self):
return Template("CONST $name=$value$manual").substitute(name=self.name,
@ -227,7 +244,6 @@ class ClassPropInfo():
class ClassInfo(GeneralInfo):
def __init__(self, decl, namespaces=[]): # [ 'class/struct cname', ': base', [modlist] ]
GeneralInfo.__init__(self, "class", decl, namespaces)
self.cname = get_cname(self.name)
self.methods = []
self.methods_suffixes = {}
self.consts = [] # using a list to save the occurrence order
@ -242,6 +258,18 @@ class ClassInfo(GeneralInfo):
for m in decl[2]:
if m.startswith("="):
self.jname = m[1:]
if self.classpath:
prefix = self.classpath.replace('.', '_')
self.name = '%s_%s' % (prefix, self.name)
self.jname = '%s_%s' % (prefix, self.jname)
if self.namespace in namespaces_dict:
prefix = namespaces_dict[self.namespace]
if prefix:
self.name = '%s_%s' % (prefix, self.name)
self.jname = '%s_%s' % (prefix, self.jname)
self.base = ''
if decl[1]:
#self.base = re.sub(r"\b"+self.jname+r"\b", "", decl[1].replace(":", "")).strip()
@ -358,11 +386,26 @@ class FuncInfo(GeneralInfo):
self.isconstructor = self.name == self.classname
if "[" in self.name:
self.jname = "getelem"
if self.namespace in namespaces_dict:
self.jname = '%s_%s' % (namespaces_dict[self.namespace], self.jname)
for m in decl[2]:
if m.startswith("="):
if m.startswith("="): # alias from WRAP_AS
self.jname = m[1:]
if self.classpath and self.classname != self.classpath:
prefix = self.classpath.replace('.', '_')
self.classname = prefix #'%s_%s' % (prefix, self.classname)
if self.isconstructor:
self.name = prefix #'%s_%s' % (prefix, self.name)
self.jname = prefix #'%s_%s' % (prefix, self.jname)
if self.namespace in namespaces_dict:
prefix = namespaces_dict[self.namespace]
if prefix:
if self.classname:
self.classname = '%s_%s' % (prefix, self.classname)
if self.isconstructor:
self.jname = '%s_%s' % (prefix, self.jname)
else:
self.jname = '%s_%s' % (prefix, self.jname)
self.static = ["","static"][ "/S" in decl[2] ]
self.ctype = re.sub(r"^CvTermCriteria", "TermCriteria", decl[1] or "")
self.args = []
@ -374,6 +417,12 @@ class FuncInfo(GeneralInfo):
arg[3] = arg_fix_map.get('attrib', arg[3]) #fixing arg attrib
self.args.append(ArgInfo(arg))
def fullClassJAVA(self):
return self.fullParentNameJAVA()
def fullClassCPP(self):
return self.fullParentNameCPP()
def __repr__(self):
return Template("FUNC <$ctype $namespace.$classpath.$name $args>").substitute(**self.__dict__)
@ -388,7 +437,8 @@ class JavaWrapperGenerator(object):
def clear(self):
self.namespaces = ["cv"]
self.classes = { "Mat" : ClassInfo([ 'class Mat', '', [], [] ], self.namespaces) }
classinfo_Mat = ClassInfo([ 'class cv.Mat', '', [], [] ], self.namespaces)
self.classes = { "Mat" : classinfo_Mat }
self.module = ""
self.Module = ""
self.ported_func_list = []
@ -411,7 +461,7 @@ class JavaWrapperGenerator(object):
type_dict.setdefault(name, {}).update(
{ "j_type" : classinfo.jname,
"jn_type" : "long", "jn_args" : (("__int64", ".nativeObj"),),
"jni_name" : "(*("+classinfo.fullName(isCPP=True)+"*)%(n)s_nativeObj)", "jni_type" : "jlong",
"jni_name" : "(*("+classinfo.fullNameCPP()+"*)%(n)s_nativeObj)", "jni_type" : "jlong",
"suffix" : "J",
"j_import" : "org.opencv.%s.%s" % (self.module, classinfo.jname)
}
@ -419,7 +469,7 @@ class JavaWrapperGenerator(object):
type_dict.setdefault(name+'*', {}).update(
{ "j_type" : classinfo.jname,
"jn_type" : "long", "jn_args" : (("__int64", ".nativeObj"),),
"jni_name" : "("+classinfo.fullName(isCPP=True)+"*)%(n)s_nativeObj", "jni_type" : "jlong",
"jni_name" : "("+classinfo.fullNameCPP()+"*)%(n)s_nativeObj", "jni_type" : "jlong",
"suffix" : "J",
"j_import" : "org.opencv.%s.%s" % (self.module, classinfo.jname)
}
@ -446,7 +496,7 @@ class JavaWrapperGenerator(object):
type_dict.setdefault("Ptr_"+name, {}).update(
{ "j_type" : classinfo.jname,
"jn_type" : "long", "jn_args" : (("__int64", ".getNativeObjAddr()"),),
"jni_name" : "*((Ptr<"+classinfo.fullName(isCPP=True)+">*)%(n)s_nativeObj)", "jni_type" : "jlong",
"jni_name" : "*((Ptr<"+classinfo.fullNameCPP()+">*)%(n)s_nativeObj)", "jni_type" : "jlong",
"suffix" : "J",
"j_import" : "org.opencv.%s.%s" % (self.module, classinfo.jname)
}
@ -489,14 +539,15 @@ class JavaWrapperGenerator(object):
def add_func(self, decl):
fi = FuncInfo(decl, namespaces=self.namespaces)
classname = fi.classname or self.Module
class_symbol_id = classname if self.isWrapped(classname) else fi.classpath.replace('.', '_') #('.'.join([fi.namespace, fi.classpath])[3:])
if classname in class_ignore_list:
logging.info('ignored: %s', fi)
elif classname in ManualFuncs and fi.jname in ManualFuncs[classname]:
logging.info('manual: %s', fi)
elif not self.isWrapped(classname):
elif not self.isWrapped(class_symbol_id):
logging.warning('not found: %s', fi)
else:
self.getClass(classname).addMethod(fi)
self.getClass(class_symbol_id).addMethod(fi)
logging.info('ok: %s', fi)
# calc args with def val
cnt = len([a for a in fi.args if a.defval])
@ -521,7 +572,7 @@ class JavaWrapperGenerator(object):
# TODO: support UMat versions of declarations (implement UMat-wrapper for Java)
parser = hdr_parser.CppHeaderParser(generate_umat_decls=False)
self.add_class( ['class ' + self.Module, '', [], []] ) # [ 'class/struct cname', ':bases', [modlist] [props] ]
self.add_class( ['class cv.' + self.Module, '', [], []] ) # [ 'class/struct cname', ':bases', [modlist] [props] ]
# scan the headers and build more descriptive maps of classes, consts, functions
includes = []
@ -582,9 +633,9 @@ class JavaWrapperGenerator(object):
report.write("\n%i def args - %i funcs" % (i, self.def_args_hist[i]))
return report.getvalue()
def fullTypeName(self, t):
def fullTypeNameCPP(self, t):
if self.isWrapped(t):
return self.getClass(t).fullName(isCPP=True)
return self.getClass(t).fullNameCPP()
else:
return cast_from(t)
@ -897,7 +948,7 @@ class JavaWrapperGenerator(object):
default = ""
elif not fi.ctype: # c-tor
if self.isSmartClass(ci):
ret = "return (jlong)(new Ptr<%(ctype)s>(_retval_));" % { 'ctype': fi.fullClass(isCPP=True) }
ret = "return (jlong)(new Ptr<%(ctype)s>(_retval_));" % { 'ctype': fi.fullClassCPP() }
else:
ret = "return (jlong) _retval_;"
elif "v_type" in type_dict[fi.ctype]: # c-tor
@ -907,9 +958,9 @@ class JavaWrapperGenerator(object):
ret = "return env->NewStringUTF(_retval_.c_str());"
default = 'return env->NewStringUTF("");'
elif self.isWrapped(fi.ctype): # wrapped class:
ret = "return (jlong) new %s(_retval_);" % self.fullTypeName(fi.ctype)
ret = "return (jlong) new %s(_retval_);" % self.fullTypeNameCPP(fi.ctype)
elif fi.ctype.startswith('Ptr_'):
c_prologue.append("typedef Ptr<%s> %s;" % (self.fullTypeName(fi.ctype[4:]), fi.ctype))
c_prologue.append("typedef Ptr<%s> %s;" % (self.fullTypeNameCPP(fi.ctype[4:]), fi.ctype))
ret = "return (jlong)(new %(ctype)s(_retval_));" % { 'ctype':fi.ctype }
elif self.isWrapped(ret_type): # pointer to wrapped class:
ret = "return (jlong) _retval_;"
@ -924,12 +975,12 @@ class JavaWrapperGenerator(object):
else:
name = prop_name + ";//"
cvname = fi.fullName(isCPP=True)
retval = self.fullTypeName(fi.ctype) + " _retval_ = " if ret else "return "
cvname = fi.fullNameCPP()
retval = self.fullTypeNameCPP(fi.ctype) + " _retval_ = " if ret else "return "
if fi.ctype == "void":
retval = ""
elif fi.ctype == "String":
retval = "cv::" + self.fullTypeName(fi.ctype) + " _retval_ = "
retval = "cv::" + self.fullTypeNameCPP(fi.ctype) + " _retval_ = "
elif fi.ctype == "string":
retval = "std::string _retval_ = "
elif "v_type" in type_dict[fi.ctype]: # vector is returned
@ -945,18 +996,18 @@ class JavaWrapperGenerator(object):
if fi.classname:
if not fi.ctype: # c-tor
if self.isSmartClass(ci):
retval = self.smartWrap(ci, fi.fullClass(isCPP=True)) + " _retval_ = "
cvname = "makePtr<" + fi.fullClass(isCPP=True) +">"
retval = self.smartWrap(ci, fi.fullClassCPP()) + " _retval_ = "
cvname = "makePtr<" + fi.fullClassCPP() +">"
else:
retval = fi.fullClass(isCPP=True) + "* _retval_ = "
cvname = "new " + fi.fullClass(isCPP=True)
retval = fi.fullClassCPP() + "* _retval_ = "
cvname = "new " + fi.fullClassCPP()
elif fi.static:
cvname = fi.fullName(isCPP=True)
cvname = fi.fullNameCPP()
else:
cvname = ("me->" if not self.isSmartClass(ci) else "(*me)->") + name
c_prologue.append(
"%(cls)s* me = (%(cls)s*) self; //TODO: check for NULL"
% { "cls" : self.smartWrap(ci, fi.fullClass(isCPP=True))}
% { "cls" : self.smartWrap(ci, fi.fullClassCPP())}
)
cvargs = []
for a in args:
@ -981,13 +1032,12 @@ class JavaWrapperGenerator(object):
clazz = ci.jname
cpp_code.write ( Template(
"""
${namespace}
JNIEXPORT $rtype JNICALL Java_org_opencv_${module}_${clazz}_$fname ($argst);
JNIEXPORT $rtype JNICALL Java_org_opencv_${module}_${clazz}_$fname
($args)
{
${namespace}
static const char method_name[] = "$module::$fname()";
try {
LOGD("%s", method_name);$prologue
@ -1014,7 +1064,7 @@ JNIEXPORT $rtype JNICALL Java_org_opencv_${module}_${clazz}_$fname
cvargs = " " + ", ".join(cvargs) + " " if cvargs else "",
default = "\n " + default if default else "",
retval = retval,
namespace = ('using namespace ' + ci.namespace.replace('.', '::') + ';') if ci.namespace else ''
namespace = ('using namespace ' + ci.namespace.replace('.', '::') + ';') if ci.namespace and ci.namespace != 'cv' else ''
) )
# adding method signature to dictionary
@ -1081,13 +1131,14 @@ JNIEXPORT $rtype JNICALL Java_org_opencv_${module}_${clazz}_$fname
self.gen_func(ci, fi)
# props
for pi in ci.props:
basename = ci.fullNameOrigin()
# getter
getter_name = ci.fullName() + ".get_" + pi.name
getter_name = basename + ".get_" + pi.name
fi = FuncInfo( [getter_name, pi.ctype, [], []], self.namespaces ) # [ funcname, return_ctype, [modifiers], [args] ]
self.gen_func(ci, fi, pi.name)
if pi.rw:
#setter
setter_name = ci.fullName() + ".set_" + pi.name
setter_name = basename + ".set_" + pi.name
fi = FuncInfo( [ setter_name, "void", [], [ [pi.ctype, pi.name, "", [], ""] ] ], self.namespaces)
self.gen_func(ci, fi, pi.name)
@ -1131,7 +1182,7 @@ JNIEXPORT void JNICALL Java_org_opencv_%(module)s_%(j_cls)s_delete
delete (%(cls)s*) self;
}
""" % {"module" : module.replace('_', '_1'), "cls" : self.smartWrap(ci, ci.fullName(isCPP=True)), "j_cls" : ci.jname.replace('_', '_1')}
""" % {"module" : module.replace('_', '_1'), "cls" : self.smartWrap(ci, ci.fullNameCPP()), "j_cls" : ci.jname.replace('_', '_1')}
)
def getClass(self, classname):