Skip to content

Commit

Permalink
* Add support for data member pointers as pseudo-FunctionPointer (…
Browse files Browse the repository at this point in the history
…issue #114)
  • Loading branch information
saudet committed Jul 29, 2016
1 parent 21c3c66 commit 1380e19
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 57 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@

* Add support for data member pointers as pseudo-`FunctionPointer` ([issue #114](https://github.com/bytedeco/javacpp/issues/114))
* Change the packaging type to `jar` since `maven-plugin` causes issues with sbt and Ivy ([issue #113](https://github.com/bytedeco/javacpp/issues/113))
* Include new `platform.compiler.debug` options inside the default properties file ([pull #90](https://github.com/bytedeco/javacpp/issues/90))
* Always use the `platform.compiler.default` options unless `@Platform(compiler="!default", ...)` is specified
Expand Down
117 changes: 79 additions & 38 deletions src/main/java/org/bytedeco/javacpp/tools/Generator.java
Original file line number Diff line number Diff line change
Expand Up @@ -768,7 +768,9 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver
String instanceTypeName = functionClassName(c);
out.println("struct JavaCPP_hidden " + instanceTypeName + " {");
out.println(" " + instanceTypeName + "() : ptr(NULL), obj(NULL) { }");
out.println(" " + returnConvention[0] + "operator()" + parameterDeclaration + ";");
if (parameterDeclaration != null && parameterDeclaration.length() > 0) {
out.println(" " + returnConvention[0] + "operator()" + parameterDeclaration + ";");
}
out.println(" " + typeName[0] + "ptr" + typeName[1] + ";");
out.println(" jobject obj; static jmethodID mid;");
out.println("};");
Expand Down Expand Up @@ -1129,7 +1131,7 @@ boolean methods(Class<?> cls) {
c = c.getSuperclass();
}
boolean[] callbackAllocators = new boolean[methods.length];
Method functionMethod = functionMethod(cls, callbackAllocators);
Method[] functionMethods = functionMethods(cls, callbackAllocators);
boolean firstCallback = true;
for (int i = 0; i < methods.length; i++) {
if (!checkPlatform(methods[i].getAnnotation(Platform.class), null)) {
Expand All @@ -1139,19 +1141,24 @@ boolean methods(Class<?> cls) {
String nativeName = mangle(cls.getName()) + "_" + mangle(methods[i].getName());
String callbackName = callbackAllocators[i] && methodInfo.parameterTypes.length > 0
? null : "JavaCPP_" + nativeName + "_callback";
if (callbackAllocators[i] && functionMethod == null) {
if (callbackAllocators[i] && functionMethods == null) {
logger.warn("No callback method call() or apply() has been not declared in \"" +
cls.getCanonicalName() + "\". No code will be generated for callback allocator.");
continue;
} else if (callbackAllocators[i] || (methods[i].equals(functionMethod) && !Modifier.isNative(methods[i].getModifiers()))) {
functions.index(cls);
Name name = methods[i].getAnnotation(Name.class);
if (name != null && name.value().length > 0 && name.value()[0].length() > 0) {
callbackName = name.value()[0];
} else if (functionMethods != null) {
for (Method functionMethod : functionMethods) {
if (functionMethod != null && (callbackAllocators[i])
|| (methods[i].equals(functionMethod) && !Modifier.isNative(methods[i].getModifiers()))) {
functions.index(cls);
Name name = methods[i].getAnnotation(Name.class);
if (name != null && name.value().length > 0 && name.value()[0].length() > 0) {
callbackName = name.value()[0];
}
callback(cls, functionMethod, callbackName, firstCallback, null);
firstCallback = false;
didSomething = true;
}
}
callback(cls, functionMethod, callbackName, firstCallback, null);
firstCallback = false;
didSomething = true;
}

if ((Modifier.isNative(methods[i].getModifiers()) || Modifier.isAbstract(methods[i].getModifiers()))
Expand Down Expand Up @@ -1487,8 +1494,9 @@ void call(MethodInformation methodInfo, String returnPrefix, boolean secondCall)
out.println(indent + " (*deallocatorAddress)(allocatedAddress);");
out.println(indent + "}");
return; // nothing else should be appended here for deallocator
} else if (methodInfo.valueGetter || methodInfo.valueSetter ||
methodInfo.memberGetter || methodInfo.memberSetter) {
} else if (!FunctionPointer.class.isAssignableFrom(methodInfo.cls) &&
(methodInfo.valueGetter || methodInfo.valueSetter ||
methodInfo.memberGetter || methodInfo.memberSetter)) {
boolean wantsPointer = false;
int k = methodInfo.parameterTypes.length-1;
if ((methodInfo.valueSetter || methodInfo.memberSetter) &&
Expand Down Expand Up @@ -1541,6 +1549,11 @@ void call(MethodInformation methodInfo, String returnPrefix, boolean secondCall)
if (methodInfo.cls.isAnnotationPresent(Namespace.class)) {
out.print("(ptr0->*(ptr->ptr))");
skipParameters = 1;
if (methodInfo.valueGetter || methodInfo.valueSetter) {
// this is get/put for a field pointer, not a real function
prefix = methodInfo.valueGetter ? "" : " = ";
suffix = "";
}
} else {
out.print("(*ptr->ptr)");
}
Expand Down Expand Up @@ -2428,12 +2441,12 @@ static String functionClassName(Class<?> cls) {
return name != null ? name.value()[0] : "JavaCPP_" + mangle(cls.getName());
}

static Method functionMethod(Class<?> cls, boolean[] callbackAllocators) {
static Method[] functionMethods(Class<?> cls, boolean[] callbackAllocators) {
if (!FunctionPointer.class.isAssignableFrom(cls)) {
return null;
}
Method[] methods = cls.getDeclaredMethods();
Method functionMethod = null;
Method[] functionMethods = new Method[3];
for (int i = 0; i < methods.length; i++) {
String methodName = methods[i].getName();
int modifiers = methods[i].getModifiers();
Expand All @@ -2450,10 +2463,15 @@ static Method functionMethod(Class<?> cls, boolean[] callbackAllocators) {
callbackAllocators[i] = true;
} else if (methodName.startsWith("call") || methodName.startsWith("apply")) {
// found a function caller method and/or callback method
functionMethod = methods[i];
functionMethods[0] = methods[i];
} else if (methodName.startsWith("get")) {
functionMethods[1] = methods[i];
} else if (methodName.startsWith("put")) {
functionMethods[2] = methods[i];
}
}
return functionMethod;
return (functionMethods[0] != null || functionMethods[1] != null || functionMethods[2] != null) ?
functionMethods : null;
}

MethodInformation methodInformation(Method method) {
Expand Down Expand Up @@ -2643,6 +2661,12 @@ MethodInformation methodInformation(Method method) {
} else if (info.memberSetter || info.valueSetter) {
info.dim = info.parameterTypes.length-1;
}
if ((info.valueGetter || info.valueSetter)
&& FunctionPointer.class.isAssignableFrom(info.cls)
&& info.cls.isAnnotationPresent(Namespace.class)) {
// a member pointer where the first argument is the object
info.dim--;
}
}

info.throwsException = null;
Expand Down Expand Up @@ -2937,9 +2961,10 @@ String[] cppTypeName(Class<?> type) {
} else if (type.isPrimitive()) {
prefix = type.getName();
} else if (FunctionPointer.class.isAssignableFrom(type)) {
Method functionMethod = functionMethod(type, null);
if (functionMethod != null) {
return cppFunctionTypeName(functionMethod);
Method[] functionMethods = functionMethods(type, null);
String[] prefixSuffix = cppFunctionTypeName(functionMethods);
if (prefixSuffix != null) {
return prefixSuffix;
}
} else {
String scopedType = cppScopeName(type);
Expand All @@ -2953,7 +2978,19 @@ String[] cppTypeName(Class<?> type) {
return new String[] { prefix, suffix };
}

String[] cppFunctionTypeName(Method functionMethod) {
String[] cppFunctionTypeName(Method... functionMethods) {
Method functionMethod = null;
if (functionMethods != null) {
for (Method m : functionMethods) {
if (m != null) {
functionMethod = m;
break;
}
}
}
if (functionMethod == null) {
return null;
}
String prefix, suffix;
Class<?> type = functionMethod.getDeclaringClass();
Convention convention = type.getAnnotation(Convention.class);
Expand All @@ -2980,25 +3017,29 @@ String[] cppFunctionTypeName(Method functionMethod) {
prefix = returnTypeName[0] + returnTypeName[1];
}
prefix += " (" + callingConvention + spaceName + "*";
suffix = ")(";
if (FunctionPointer.class.isAssignableFrom(type) && namespace != null
&& (parameterTypes.length == 0 || !Pointer.class.isAssignableFrom(parameterTypes[0]))) {
logger.warn("First parameter of caller method call() or apply() for member function pointer " +
type.getCanonicalName() + " is not a Pointer. Compilation will most likely fail.");
}
for (int j = namespace == null ? 0 : 1; j < parameterTypes.length; j++) {
String[] paramTypeName = cppAnnotationTypeName(parameterTypes[j], parameterAnnotations[j]);
AdapterInformation paramAdapterInfo = adapterInformation(false, valueTypeName(paramTypeName), parameterAnnotations[j]);
if (paramAdapterInfo != null && paramAdapterInfo.cast.length() > 0) {
suffix += paramAdapterInfo.cast + " arg" + j;
} else {
suffix += paramTypeName[0] + " arg" + j + paramTypeName[1];
}
if (j < parameterTypes.length - 1) {
suffix += ", ";
suffix = ")";
if (functionMethod == functionMethods[0]) {
// this is a real function, not get/put for a field pointer
suffix += "(";
if (FunctionPointer.class.isAssignableFrom(type) && namespace != null
&& (parameterTypes.length == 0 || !Pointer.class.isAssignableFrom(parameterTypes[0]))) {
logger.warn("First parameter of caller method call() or apply() for member function pointer " +
type.getCanonicalName() + " is not a Pointer. Compilation will most likely fail.");
}
for (int j = namespace == null ? 0 : 1; j < parameterTypes.length; j++) {
String[] paramTypeName = cppAnnotationTypeName(parameterTypes[j], parameterAnnotations[j]);
AdapterInformation paramAdapterInfo = adapterInformation(false, valueTypeName(paramTypeName), parameterAnnotations[j]);
if (paramAdapterInfo != null && paramAdapterInfo.cast.length() > 0) {
suffix += paramAdapterInfo.cast + " arg" + j;
} else {
suffix += paramTypeName[0] + " arg" + j + paramTypeName[1];
}
if (j < parameterTypes.length - 1) {
suffix += ", ";
}
}
suffix += ")";
}
suffix += ")";
if (type.isAnnotationPresent(Const.class)) {
suffix += " const";
}
Expand Down
75 changes: 56 additions & 19 deletions src/main/java/org/bytedeco/javacpp/tools/Parser.java
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,7 @@ Declarator declarator(Context context, String defaultName, int infoNumber, boole
dcl.cppName = "";
Info groupInfo = null;
Declaration definition = new Declaration();
boolean fieldPointer = false;
if (tokens.get().match('(') || (typedef && tokens.get(1).match('('))) {
// probably a function pointer declaration
if (tokens.get().match('(')) {
Expand Down Expand Up @@ -803,7 +804,29 @@ Declarator declarator(Context context, String defaultName, int infoNumber, boole
}
} else if (tokens.get().match(Token.IDENTIFIER)) {
for (Token token = tokens.get(); !token.match(Token.EOF); token = tokens.next()) {
if (token.match("::")) {
if (dcl.cppName.length() > 0 && token.match('*')) {
// a data member pointer or something
dcl.cppName = dcl.cppName.substring(0, dcl.cppName.length() - 2);
for (String name : context.qualify(dcl.cppName)) {
if ((groupInfo = infoMap.getFirst(name, false)) != null) {
dcl.cppName = name;
break;
} else if (infoMap.getFirst(name) != null) {
dcl.cppName = name;
}
}
definition.text += "@Namespace(\"" + dcl.cppName + "\") ";

for (token = tokens.get(); !token.match(Token.EOF); token = tokens.next()) {
if (token.match('*')) {
indirections2++;
} else {
break;
}
}
dcl.cppName = token.match(Token.IDENTIFIER) ? token.toString() : "";
fieldPointer = groupInfo != null;
} else if (token.match("::")) {
dcl.cppName += token;
} else if (token.match(Token.OPERATOR)) {
dcl.operator = true;
Expand Down Expand Up @@ -1024,7 +1047,7 @@ Declarator declarator(Context context, String defaultName, int infoNumber, boole
}

// pick the Java name from the InfoMap if appropriate
String originalName = dcl.javaName;
String originalName = fieldPointer ? groupInfo.pointerTypes[0] : dcl.javaName;
if (attr == null && defaultName == null && info != null && info.javaNames != null && info.javaNames.length > 0
&& (dcl.operator || !info.cppNames[0].contains("<") || (context.templateMap != null && context.templateMap.type == null))) {
dcl.javaName = info.javaNames[0];
Expand All @@ -1039,9 +1062,11 @@ Declarator declarator(Context context, String defaultName, int infoNumber, boole
// deal with function parameters and function pointers
dcl.type = type;
dcl.signature = dcl.javaName;
if (dcl.parameters != null) {
dcl.infoNumber = Math.max(dcl.infoNumber, dcl.parameters.infoNumber);
if (indirections2 == 0 && !typedef) {
if (dcl.parameters != null || fieldPointer) {
if (dcl.parameters != null) {
dcl.infoNumber = Math.max(dcl.infoNumber, dcl.parameters.infoNumber);
}
if (dcl.parameters != null && indirections2 == 0 && !typedef) {
dcl.signature += dcl.parameters.signature;
} else {
String cppType = "";
Expand All @@ -1056,16 +1081,18 @@ Declarator declarator(Context context, String defaultName, int infoNumber, boole
}
cppType += " (*)(";
String separator = "";
for (Declarator d : dcl.parameters.declarators) {
if (d != null) {
cppType += separator + d.type.cppName;
for (int i = 0; i < d.indirections; i++) {
cppType += "*";
}
if (d.reference) {
cppType += "&";
if (dcl.parameters != null) {
for (Declarator d : dcl.parameters.declarators) {
if (d != null) {
cppType += separator + d.type.cppName;
for (int i = 0; i < d.indirections; i++) {
cppType += "*";
}
if (d.reference) {
cppType += "&";
}
separator = ", ";
}
separator = ", ";
}
}
info = infoMap.getFirst(cppType += ")");
Expand All @@ -1078,10 +1105,10 @@ Declarator declarator(Context context, String defaultName, int infoNumber, boole
functionType = info.pointerTypes[0];
} else if (typedef) {
functionType = originalName;
} else if (dcl.parameters.signature.length() > 0) {
} else if (dcl.parameters != null && dcl.parameters.signature.length() > 0) {
functionType += dcl.parameters.signature;
} else if (!type.javaName.equals("void")) {
functionType = type.javaName + "_" + functionType;
functionType = Character.toUpperCase(type.javaName.charAt(0)) + type.javaName.substring(1) + "_" + functionType;
}
if (info != null && info.annotations != null) {
for (String s : info.annotations) {
Expand All @@ -1095,16 +1122,26 @@ Declarator declarator(Context context, String defaultName, int infoNumber, boole
" public " + functionType + "(Pointer p) { super(p); }\n" +
(groupInfo != null ? "" :
" protected " + functionType + "() { allocate(); }\n" +
" private native void allocate();\n") +
" private native void allocate();\n");
if (fieldPointer) {
definition.text +=
" public native " + type.annotations + type.javaName + " get(" + groupInfo.pointerTypes[0] + " o);\n" +
" public native " + functionType + " put(" + groupInfo.pointerTypes[0] + " o, " + type.annotations + type.javaName + " v);\n" +
"}\n";
} else {
definition.text +=
" public native " + type.annotations + type.javaName + " call" +
(groupInfo != null ? "(" + groupInfo.pointerTypes[0] + " o" + (dcl.parameters.list.charAt(1) == ')' ?
")" : ", " + dcl.parameters.list.substring(1)) : dcl.parameters.list) + ";\n" +
"}\n";
}
definition.signature = functionType;
definition.declarator = new Declarator();
definition.declarator.parameters = dcl.parameters;
dcl.definition = definition;
dcl.parameters = null;
if (!fieldPointer) {
dcl.parameters = null;
}
type.annotations = "";
type.javaName = functionType;
}
Expand Down Expand Up @@ -1732,7 +1769,7 @@ boolean variable(Context context, DeclarationList declList) throws ParserExcepti
decl = new Declaration();
tokens.index = backIndex;
dcl = declarator(context, null, -1, false, n, false, true);
if (dcl == null) {
if (dcl == null || dcl.cppName == null) {
break;
}
decl.declarator = dcl;
Expand Down

0 comments on commit 1380e19

Please sign in to comment.