Skip to content

Commit

Permalink
* Add Info.friendly to have Parser map some friend functions t…
Browse files Browse the repository at this point in the history
…o Java methods (pull #649)
  • Loading branch information
HGuillemet committed Feb 14, 2023
1 parent 232dcb0 commit 5f81c23
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 8 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@

* Add `Info.friendly` to have `Parser` map some `friend` functions to Java methods ([pull #649](https://github.com/bytedeco/javacpp/pull/649))
* Add `Loader.loadProperties(boolean forceReload)` to reset platform properties ([issue deepjavalibrary/djl#2318](https://github.com/deepjavalibrary/djl/issues/2318))
* Prevent `TokenIndexer` from recursively expanding macros
* Fix `Generator` passing empty `String` objects on callback for arguments using adapters
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/org/bytedeco/javacpp/tools/Info.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public Info(Info i) {
define = i.define;
enumerate = i.enumerate;
flatten = i.flatten;
friendly = i.friendly;
immutable = i.immutable;
beanify = i.beanify;
objectify = i.objectify;
Expand Down Expand Up @@ -97,6 +98,9 @@ public Info(Info i) {
/** Outputs declarations for this class into their subclasses as well.
* Also adds methods for explicit casting, as done for multiple inheritance by default. */
boolean flatten = false;
/** Maps friend functions. Only functions having in their argument list an instance of the class they are friend
* of are currently supported. They are mapped as instance methods of the class. */
boolean friendly = false;
/** Disables generation of setters for public data members of a class */
boolean immutable = false;
/** Adds JavaBeans-style prefixes to getters and setters of public data members of a class */
Expand Down Expand Up @@ -136,6 +140,8 @@ public Info(Info i) {
public Info enumerate(boolean enumerate) { this.enumerate = enumerate; return this; }
public Info flatten() { this.flatten = true; return this; }
public Info flatten(boolean flatten) { this.flatten = flatten; return this; }
public Info friendly() { this.friendly = true; return this; }
public Info friendly(boolean friendly) { this.friendly = friendly; return this; }
public Info immutable() { this.immutable = true; return this; }
public Info immutable(boolean immutable) { this.immutable = immutable; return this; }
public Info beanify() { this.beanify = true; return this; }
Expand Down
59 changes: 51 additions & 8 deletions src/main/java/org/bytedeco/javacpp/tools/Parser.java
Original file line number Diff line number Diff line change
Expand Up @@ -2114,9 +2114,7 @@ Parameters parameters(Context context, int infoNumber, boolean useDefaults) thro
params.list += "/*" + defaultToken + defaultValue + "*/";
}
params.signature += '_';
for (char c : dcl.type.javaName.substring(dcl.type.javaName.lastIndexOf(' ') + 1).toCharArray()) {
params.signature += Character.isJavaIdentifierPart(c) ? c : '_';
}
params.signature += dcl.type.signature();
params.names += (count > 1 ? ", " : "") + paramName;
if (dcl.javaName.startsWith("arg")) {
try {
Expand Down Expand Up @@ -2331,8 +2329,10 @@ boolean function(Context context, DeclarationList declList) throws ParserExcepti
break;
}
}
if (type.friend || tokens.get().match("&&") || (context.javaName == null && localNamespace > 0) || (info != null && info.skip)) {
// this is a friend declaration, an rvalue function, or a member function definition or specialization, skip over
Info info2 = infoMap.getFirst(null);
boolean friendly = info != null ? info.friendly : info2 != null ? info2.friendly : false;
if ((type.friend && !friendly) || tokens.get().match("&&") || (context.javaName == null && localNamespace > 0) || (info != null && info.skip)) {
// this is an unwanted friend declaration, an rvalue function, or a member function definition or specialization, skip over
while (!tokens.get().match(':', '{', ';', Token.EOF)) {
tokens.next();
}
Expand Down Expand Up @@ -2376,6 +2376,11 @@ boolean function(Context context, DeclarationList declList) throws ParserExcepti
decl.function = true;
declList.add(decl);
return true;
} else if (type.friend) {
// The friend function may be accessible only through ADL, so disable namespace lookup.
// Map the function to a private static method and create a public Java instance method below
// that calls this static method.
modifiers = "private static native @Namespace ";
} else if (type.staticMember || context.javaName == null) {
modifiers = "public " + ((info != null && info.objectify) || context.objectify ? "" : "static ") + "native ";
if (tokens.isCFile) {
Expand All @@ -2387,6 +2392,7 @@ boolean function(Context context, DeclarationList declList) throws ParserExcepti
boolean first = true;
for (int n = -2; n < Integer.MAX_VALUE; n++) {
decl = new Declaration();
Declaration extraDecl = null; // Secondary declaration to add. Currently only used for friends.
tokens.index = startIndex;
boolean useDefaults = (info == null || !info.skipDefaults) && n % 2 != 0;
if ((type.constructor || type.destructor || type.operator) && params != null) {
Expand Down Expand Up @@ -2512,8 +2518,43 @@ boolean function(Context context, DeclarationList declList) throws ParserExcepti
tokens.next();
}

// skip over non-const function within const class
if (!decl.constMember && context.constName != null) {
/* If it's a friend function, and we want friend mapping, check if it accepts an argument of the enclosing type.
If it does, add a Java instance method calling the static native method.
If it does not, skip over. */
if (type.friend && friendly) {
Declarator[] paramDeclarators = dcl.parameters.declarators;
String signature = dcl.javaName;
String argList = "", staticArgList = "";
boolean foundThis = false;
for (Declarator paramDecl : paramDeclarators) {
if (staticArgList.length() > 0) {
staticArgList += ", ";
}
if (!foundThis && paramDecl.type.cppName.equals(context.cppName)) {
foundThis = true;
staticArgList += "this";
} else {
if (argList.length() > 0) {
argList += ", ";
}
argList += paramDecl.type.javaName + " " + paramDecl.javaName;
signature += '_' + paramDecl.type.signature();
staticArgList += paramDecl.javaName;
}
}
if (foundThis) {
extraDecl = new Declaration();
extraDecl.signature = signature;
extraDecl.declarator = dcl; // Used in group to recognize friends
extraDecl.text = "public " + dcl.type.javaName + " " + dcl.javaName + "(" + argList + ") { "
+ (dcl.type.javaName.equals("void") ? "" : "return ") + dcl.javaName + "(" + staticArgList + "); }\n";
} else {
friendly = false;
}
}

// skip over friend functions we can't map and non-const function within const class
if ((type.friend && !friendly) || !decl.constMember && context.constName != null) {
decl.text = spacing;
declList.add(decl);
return true;
Expand Down Expand Up @@ -2582,6 +2623,7 @@ boolean function(Context context, DeclarationList declList) throws ParserExcepti
if (dcl.javaName.length() > 0 && !found && (!type.destructor || (info != null && info.javaText != null))) {
if (declList.add(decl, fullname)) {
first = false;
if (extraDecl != null) declList.add(extraDecl);
}
if (type.virtual && context.virtualize) {
break;
Expand Down Expand Up @@ -3614,7 +3656,8 @@ boolean group(Context context, DeclarationList declList) throws ParserException
}
}
for (Declaration d : declList2) {
if (!d.inaccessible && (d.declarator == null || d.declarator.type == null
if ((!d.inaccessible || d.declarator != null && d.declarator.type.friend)
&& (d.declarator == null || d.declarator.type == null
|| !d.declarator.type.constructor || !abstractClass || (info != null && info.virtualize))) {
decl.text += d.text;
}
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/org/bytedeco/javacpp/tools/Type.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,12 @@ class Type {
return false;
}
}

String signature() {
String sig = "";
for (char c : javaName.substring(javaName.lastIndexOf(' ') + 1).toCharArray()) {
sig += Character.isJavaIdentifierPart(c) ? c : '_';
}
return sig;
}
}

0 comments on commit 5f81c23

Please sign in to comment.