diff --git a/CHANGELOG.md b/CHANGELOG.md
index df64ceac4..e7c34381c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,5 @@
+ * Support multiple instances of `FunctionPointer` subclasses, up to the value in `@Allocator(max=...)` ([issue bytedeco/javacpp-presets#683](https://github.com/bytedeco/javacpp-presets/issues/683))
* Allow suffixing library names with `:` to specify exact relative paths to libraries, ignoring any additional prefix or suffix
* Prevent `Loader.load()` from trying to load library files that do not exist or to create symbolic links to them
* Let `Loader.load()` extract libraries suffixed with `##`, but still ignored for copying by `Builder`
diff --git a/README.md b/README.md
index 4486a6ee2..465e378dc 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
JavaCPP
=======
-[![Join the chat at https://gitter.im/bytedeco/javacpp](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/bytedeco/javacpp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.bytedeco/javacpp/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.bytedeco/javacpp) [![Sonatype Nexus (Snapshots)](https://img.shields.io/nexus/s/https/oss.sonatype.org/org.bytedeco/javacpp.svg)](http://bytedeco.org/builds/) [![Build Status](https://travis-ci.org/bytedeco/javacpp.svg?branch=master)](https://travis-ci.org/bytedeco/javacpp)
+[![Gitter](https://badges.gitter.im/bytedeco/javacpp.svg)](https://gitter.im/bytedeco/javacpp) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.bytedeco/javacpp/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.bytedeco/javacpp) [![Sonatype Nexus (Snapshots)](https://img.shields.io/nexus/s/https/oss.sonatype.org/org.bytedeco/javacpp.svg)](http://bytedeco.org/builds/) [![Build Status](https://travis-ci.org/bytedeco/javacpp.svg?branch=master)](https://travis-ci.org/bytedeco/javacpp)
Introduction
diff --git a/src/main/java/org/bytedeco/javacpp/annotation/Allocator.java b/src/main/java/org/bytedeco/javacpp/annotation/Allocator.java
index d65b3054f..9ec723d30 100644
--- a/src/main/java/org/bytedeco/javacpp/annotation/Allocator.java
+++ b/src/main/java/org/bytedeco/javacpp/annotation/Allocator.java
@@ -5,6 +5,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+import org.bytedeco.javacpp.FunctionPointer;
import org.bytedeco.javacpp.Pointer;
import org.bytedeco.javacpp.tools.Generator;
@@ -20,6 +21,8 @@
* the given arguments, and initializes the {@link Pointer#address} as well as
* the {@link Pointer#deallocator} with {@code NativeDeallocator}, based on the
* {@code delete} operator, if not additionally annotated with {@link NoDeallocator}.
+ *
+ * Can also be used on classes to set the {@link #max} value for enclosed function pointers.
*
* @see Pointer#init(long, long, long, long)
* @see Generator
@@ -27,5 +30,9 @@
* @author Samuel Audet
*/
@Documented @Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.METHOD})
-public @interface Allocator { }
+@Target({ElementType.TYPE, ElementType.METHOD})
+public @interface Allocator {
+ /** The maximum number of instances that can be allocated in the case of a {@link FunctionPointer} subclass.
+ * Does not affect the underlying function object or other {@link Pointer} which have no such allocation limits. */
+ int max() default 10;
+}
diff --git a/src/main/java/org/bytedeco/javacpp/tools/Generator.java b/src/main/java/org/bytedeco/javacpp/tools/Generator.java
index 61bff5519..94ef7fde8 100644
--- a/src/main/java/org/bytedeco/javacpp/tools/Generator.java
+++ b/src/main/java/org/bytedeco/javacpp/tools/Generator.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011-2018 Samuel Audet
+ * Copyright (C) 2011-2019 Samuel Audet
*
* Licensed either under the Apache License, Version 2.0, or (at your option)
* under the terms of the GNU General Public License as published by
@@ -39,8 +39,8 @@
import java.nio.LongBuffer;
import java.nio.ShortBuffer;
import java.util.Arrays;
-import java.util.HashMap;
import java.util.Iterator;
+import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
@@ -191,10 +191,10 @@ public boolean generate(String sourceFilename, String headerFilename, String loa
deallocators = new IndexedSet();
arrayDeallocators = new IndexedSet();
jclasses = new IndexedSet();
- members = new HashMap>();
- virtualFunctions = new HashMap>();
- virtualMembers = new HashMap>();
- annotationCache = new HashMap();
+ members = new LinkedHashMap>();
+ virtualFunctions = new LinkedHashMap>();
+ virtualMembers = new LinkedHashMap>();
+ annotationCache = new LinkedHashMap();
mayThrowExceptions = false;
usesAdapters = false;
passesStrings = false;
@@ -1327,9 +1327,12 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver
String name = "JavaCPP_" + mangle(c.getName());
out.print("static void " + name + "_deallocate(void *p) { ");
if (FunctionPointer.class.isAssignableFrom(c)) {
- String typeName = functionClassName(c) + "*";
- out.println("JNIEnv *e; bool a = JavaCPP_getEnv(&e); if (e != NULL) e->DeleteWeakGlobalRef((jweak)(("
- + typeName + ")p)->obj); delete (" + typeName + ")p; JavaCPP_detach(a); }");
+ String typeName = functionClassName(c);
+ out.println("\n int n = sizeof(" + typeName + "_instances) / sizeof(" + typeName + "_instances[0]);"
+ + "\n for (int i = 0; i < n; i++) { if (" + typeName + "_instances[i].obj == (("
+ + typeName + "*)p)->obj) " + typeName + "_instances[i].obj = NULL; }"
+ + "\n JNIEnv *e; bool a = JavaCPP_getEnv(&e); if (e != NULL) e->DeleteWeakGlobalRef((jweak)(("
+ + typeName + "*)p)->obj); delete (" + typeName + "*)p; JavaCPP_detach(a); }");
} else if (virtualFunctions.containsKey(c)) {
String[] typeName = cppTypeName(c);
String valueTypeName = valueTypeName(typeName);
@@ -1347,7 +1350,7 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver
out.println("static void " + name + "_deallocateArray(void* p) { delete[] (" + typeName[0] + typeName[1] + ")p; }");
}
out.println();
- out.println("static const char* JavaCPP_members[" + jclasses.size() + "][" + maxMemberSize + 1 + "] = {");
+ out.println("static const char* JavaCPP_members[" + jclasses.size() + "][" + (maxMemberSize + 1) + "] = {");
classIterator = jclasses.iterator();
while (classIterator.hasNext()) {
out.print(" { ");
@@ -1367,7 +1370,7 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver
}
}
out.println(" };");
- out.println("static int JavaCPP_offsets[" + jclasses.size() + "][" + maxMemberSize + 1 + "] = {");
+ out.println("static int JavaCPP_offsets[" + jclasses.size() + "][" + (maxMemberSize + 1) + "] = {");
classIterator = jclasses.iterator();
while (classIterator.hasNext()) {
out.print(" { ");
@@ -1733,7 +1736,7 @@ boolean methods(Class> cls) {
if (name != null && name.value().length > 0 && name.value()[0].length() > 0) {
callbackName = name.value()[0];
}
- callback(cls, functionMethod, callbackName, firstCallback, null);
+ callback(cls, functionMethod, callbackName, methodInfo.allocatorMax, firstCallback, null);
firstCallback = false;
didSomething = true;
}
@@ -1743,7 +1746,8 @@ boolean methods(Class> cls) {
if ((Modifier.isNative(methods[i].getModifiers()) || Modifier.isAbstract(methods[i].getModifiers()))
&& !methodInfo.valueGetter && !methodInfo.valueSetter && !methodInfo.memberGetter && !methodInfo.memberSetter
&& !cls.isInterface() && (methods[i].isAnnotationPresent(Virtual.class) || methodInfo.allocator)) {
- callback(cls, methods[i], methodInfo.memberName[0], !methodInfo.allocator, methodInfo);
+ // also process virtual methods and their allocators as callbacks
+ callback(cls, methods[i], methodInfo.memberName[0], methodInfo.allocatorMax, !methodInfo.allocator, methodInfo);
}
if (!Modifier.isNative(methods[i].getModifiers())) {
@@ -1773,7 +1777,7 @@ boolean methods(Class> cls) {
out.println(") {");
if (callbackAllocators[i]) {
- callbackAllocator(cls, callbackName);
+ callbackAllocator(cls, callbackName, methodInfo.allocatorMax);
continue;
} else if (!Modifier.isStatic(methodInfo.modifiers) && Pointer.class.isAssignableFrom(cls)
&& !methodInfo.allocator && !methodInfo.arrayAllocator && !methodInfo.deallocator) {
@@ -1793,7 +1797,7 @@ boolean methods(Class> cls) {
jclasses.index(NullPointerException.class) + "), \"This pointer address is NULL.\");");
out.println(" return" + (methodInfo.returnType == void.class ? ";" : " 0;"));
out.println(" }");
- if (FunctionPointer.class.isAssignableFrom(cls)) {
+ if (FunctionPointer.class.isAssignableFrom(cls) && !methodInfo.valueGetter && !methodInfo.valueSetter) {
out.println(" if (ptr->ptr == NULL) {");
out.println(" env->ThrowNew(JavaCPP_getClass(env, " +
jclasses.index(NullPointerException.class) + "), \"This function pointer address is NULL.\");");
@@ -2616,7 +2620,7 @@ void parametersAfter(MethodInformation methodInfo) {
}
}
- void callback(Class> cls, Method callbackMethod, String callbackName, boolean needDefinition, MethodInformation methodInfo) {
+ void callback(Class> cls, Method callbackMethod, String callbackName, int allocatorMax, boolean needDefinition, MethodInformation methodInfo) {
Class> callbackReturnType = callbackMethod.getReturnType();
Class>[] callbackParameterTypes = callbackMethod.getParameterTypes();
Annotation[] callbackAnnotations = callbackMethod.getAnnotations();
@@ -2692,7 +2696,7 @@ void callback(Class> cls, Method callbackMethod, String callbackName, boolean
}
memberList.add(member);
} else if (callbackName != null) {
- callbacks.index("static " + instanceTypeName + " " + callbackName + "_instance;");
+ callbacks.index("static " + instanceTypeName + " " + instanceTypeName + "_instances[" + allocatorMax + "];");
Convention convention = cls.getAnnotation(Convention.class);
if (convention != null && !convention.extern().equals("C")) {
out.println("extern \"" + convention.extern() + "\" {");
@@ -2700,27 +2704,38 @@ void callback(Class> cls, Method callbackMethod, String callbackName, boolean
out2.println("extern \"" + convention.extern() + "\" {");
}
}
- if (out2 != null) {
- out2.println("JNIIMPORT " + returnConvention[0] + (returnConvention.length > 1 ?
- returnConvention[1] : "") + callbackName + parameterDeclaration + ";");
- }
- out.println("JNIEXPORT " + returnConvention[0] + (returnConvention.length > 1 ?
- returnConvention[1] : "") + callbackName + parameterDeclaration + " {");
- out.print((callbackReturnType != void.class ? " return " : " ") + callbackName + "_instance(");
- for (int j = 0; j < callbackParameterTypes.length; j++) {
- out.print("arg" + j);
- if (j < callbackParameterTypes.length - 1) {
- out.print(", ");
+ for (int i = 0; i < allocatorMax; i++) {
+ if (out2 != null) {
+ out2.println("JNIIMPORT " + returnConvention[0] + (returnConvention.length > 1 ?
+ returnConvention[1] : "") + callbackName + (i > 0 ? i : "") + parameterDeclaration + ";");
+ }
+ out.println("JNIEXPORT " + returnConvention[0] + (returnConvention.length > 1 ?
+ returnConvention[1] : "") + callbackName + (i > 0 ? i : "") + parameterDeclaration + " {");
+ out.print((callbackReturnType != void.class ? " return " : " ") + instanceTypeName + "_instances[" + i + "](");
+ for (int j = 0; j < callbackParameterTypes.length; j++) {
+ out.print("arg" + j);
+ if (j < callbackParameterTypes.length - 1) {
+ out.print(", ");
+ }
}
+ out.println(");");
+ out.println("}");
}
- out.println(");");
- out.println("}");
if (convention != null && !convention.extern().equals("C")) {
out.println("}");
if (out2 != null) {
out2.println("}");
}
}
+ out.println("static " + returnConvention[0] + "(*" + (returnConvention.length > 1 ?
+ returnConvention[1] : "") + callbackName + "s[" + allocatorMax + "])" + parameterDeclaration + " = {");
+ for (int i = 0; i < allocatorMax; i++) {
+ out.print(" " + callbackName + (i > 0 ? i : ""));
+ if (i + 1 < allocatorMax) {
+ out.println(",");
+ }
+ }
+ out.println(" };");
firstLine = returnConvention[0] + instanceTypeName + "::operator()" + parameterDeclaration + " {";
}
@@ -2913,7 +2928,12 @@ void callback(Class> cls, Method callbackMethod, String callbackName, boolean
out.println(" } else {");
out.println(" env->SetLongField(obj, JavaCPP_addressFID, ptr_to_jlong(this));");
out.println(" }");
- out.println(" ptr = &" + callbackName + ";");
+ out.println(" for (int i = 0; i < " + allocatorMax + "; i++) {");
+ out.println(" if (this == &" + instanceTypeName + "_instances[i]) {");
+ out.println(" ptr = " + callbackName + "s[i];");
+ out.println(" break;");
+ out.println(" }");
+ out.println(" }");
out.println(" }");
out.println(" if (mid == NULL) {");
out.println(" mid = JavaCPP_getMethodID(env, " + jclasses.index(cls) + ", \"" + callbackMethod.getName() + "\", \"(" +
@@ -3079,9 +3099,8 @@ void callback(Class> cls, Method callbackMethod, String callbackName, boolean
out.println("}");
}
- void callbackAllocator(Class cls, String callbackName) {
- // XXX: Here, we should actually allocate new trampolines on the heap somehow...
- // For now it just bumps out from the global variable the last object that called this method
+ void callbackAllocator(Class> cls, String callbackName, int allocatorMax) {
+ // XXX: Make callback function pointer allocation more thread safe
String[] typeName = cppTypeName(cls);
String instanceTypeName = functionClassName(cls);
out.println(" obj = env->NewWeakGlobalRef(obj);");
@@ -3091,12 +3110,19 @@ void callbackAllocator(Class cls, String callbackName) {
out.println(" }");
out.println(" " + instanceTypeName + "* rptr = new (std::nothrow) " + instanceTypeName + ";");
out.println(" if (rptr != NULL) {");
- out.println(" rptr->ptr = " + (callbackName == null ? "(" + typeName[0] + typeName[1] + ")jlong_to_ptr(arg0)" : "&" + callbackName) + ";");
out.println(" rptr->obj = obj;");
out.println(" JavaCPP_initPointer(env, obj, rptr, 1, rptr, &JavaCPP_" + mangle(cls.getName()) + "_deallocate);");
deallocators.index(cls);
if (callbackName != null) {
- out.println(" " + callbackName + "_instance = *rptr;");
+ out.println(" for (int i = 0; i < " + allocatorMax + "; i++) {");
+ out.println(" if (" + instanceTypeName + "_instances[i].obj == NULL) {");
+ out.println(" rptr->ptr = " + callbackName + "s[i];");
+ out.println(" " + instanceTypeName + "_instances[i] = *rptr;");
+ out.println(" break;");
+ out.println(" }");
+ out.println(" }");
+ } else {
+ out.println(" rptr->ptr = (" + typeName[0] + typeName[1] + ")jlong_to_ptr(arg0);");
}
out.println(" }");
out.println("}");
@@ -3151,6 +3177,7 @@ MethodInformation methodInformation(Method method) {
Name name = method.getAnnotation(Name.class);
info.memberName = name != null ? name.value() : new String[] { info.name };
Index index = method.getAnnotation(Index.class);
+ info.allocatorMax = allocatorMax(info.cls, info.method);
info.dim = index != null ? index.value() : 0;
info.parameterTypes = method.getParameterTypes();
info.parameterAnnotations = method.getParameterAnnotations();
@@ -3355,6 +3382,25 @@ MethodInformation methodInformation(Method method) {
return info;
}
+ static int allocatorMax(Class> cls, Method method) {
+ Allocator a = method.getAnnotation(Allocator.class);
+ while (a == null && cls != null) {
+ if ((a = cls.getAnnotation(Allocator.class)) != null) {
+ break;
+ }
+ if (cls.getEnclosingClass() != null) {
+ cls = cls.getEnclosingClass();
+ } else {
+ cls = cls.getSuperclass();
+ }
+ }
+ try {
+ return a != null ? a.max() : (int)Allocator.class.getDeclaredMethod("max").getDefaultValue();
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
static boolean criticalRegion(Class> cls, Method method) {
boolean criticalRegion = baseClasses.contains(cls) ||
method.isAnnotationPresent(CriticalRegion.class);
@@ -3570,9 +3616,16 @@ static String constValueTypeName(String ... typeName) {
static String valueTypeName(String ... typeName) {
String type = typeName[0];
if (type.startsWith("const ")) {
- type = type.substring(6, type.length()-1);
- } else if (type.endsWith("*") || type.endsWith("&")) {
- type = type.substring(0, type.length()-1);
+ type = type.substring(6);
+ }
+ if (type.endsWith(" const")) {
+ type = type.substring(0, type.length() - 6);
+ }
+ if (type.endsWith("*") || type.endsWith("&")) {
+ type = type.substring(0, type.length() - 1);
+ }
+ if (type.endsWith(" const")) {
+ type = type.substring(0, type.length() - 6);
}
return type;
}
@@ -3663,12 +3716,12 @@ String[] cppCastTypeName(Class> type, Annotation ... annotations) {
typeName = cppTypeName(type);
if (typeName[0].contains("(*")) {
// function pointer
- if (b.length > 0 && b[0] && !typeName[0].endsWith("const")) {
- typeName[0] += "const";
+ if (b.length > 0 && b[0] && !typeName[0].endsWith(" const")) {
+ typeName[0] += " const";
}
} else {
- if (b.length > 1 && b[1] && !typeName[0].endsWith(" const *")) {
- typeName[0] = valueTypeName(typeName) + " const *";
+ if (b.length > 1 && b[1] && !typeName[0].endsWith(" const")) {
+ typeName[0] += " const";
}
if (b.length > 0 && b[0] && !typeName[0].startsWith("const ")) {
typeName[0] = "const " + typeName[0];
diff --git a/src/main/java/org/bytedeco/javacpp/tools/MethodInformation.java b/src/main/java/org/bytedeco/javacpp/tools/MethodInformation.java
index f37029c66..e9557ba32 100644
--- a/src/main/java/org/bytedeco/javacpp/tools/MethodInformation.java
+++ b/src/main/java/org/bytedeco/javacpp/tools/MethodInformation.java
@@ -36,7 +36,7 @@ public class MethodInformation {
int modifiers;
Class> returnType;
String name, memberName[];
- int dim;
+ int allocatorMax, dim;
boolean[] parameterRaw;
Class>[] parameterTypes;
Annotation[][] parameterAnnotations;
diff --git a/src/main/java/org/bytedeco/javacpp/tools/Parser.java b/src/main/java/org/bytedeco/javacpp/tools/Parser.java
index 2681b2356..e1b21ea9c 100644
--- a/src/main/java/org/bytedeco/javacpp/tools/Parser.java
+++ b/src/main/java/org/bytedeco/javacpp/tools/Parser.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013-2018 Samuel Audet
+ * Copyright (C) 2013-2019 Samuel Audet
*
* Licensed either under the Apache License, Version 2.0, or (at your option)
* under the terms of the GNU General Public License as published by
@@ -207,9 +207,6 @@ void containers(Context context, DeclarationList declList) throws ParserExceptio
if (valueType.constValue && !cast.startsWith("const ")) {
cast = "const " + cast;
}
- if (valueType.constPointer && !cast.endsWith(" const")) {
- cast = cast + " const";
- }
if (valueType.indirections > 0) {
for (int i = 0; i < valueType.indirections; i++) {
cast += "*";
@@ -220,6 +217,9 @@ void containers(Context context, DeclarationList declList) throws ParserExceptio
if (valueType.reference) {
cast += "&";
}
+ if (valueType.constPointer && !cast.endsWith(" const")) {
+ cast = cast + " const";
+ }
valueType.annotations = "@Cast(\"" + cast + "\") " + valueType.annotations;
}
String arrayBrackets = "";
@@ -564,15 +564,15 @@ Type type(Context context, boolean definition) throws ParserException {
if (t.constValue && !s.startsWith("const ")) {
s = "const " + s;
}
- if (t.constPointer && !s.endsWith(" const")) {
- s = s + " const";
- }
for (int i = 0; i < t.indirections; i++) {
s += "*";
}
if (t.reference) {
s += "&";
}
+ if (t.constPointer && !s.endsWith(" const")) {
+ s = s + " const";
+ }
type.cppName += s;
separator = ",";
}
@@ -709,6 +709,10 @@ Type type(Context context, boolean definition) throws ParserException {
type.constValue = true;
type.cppName = type.cppName.substring(6);
}
+ if (type.cppName.endsWith(" const")) {
+ type.constPointer = true;
+ type.cppName = type.cppName.substring(0, type.cppName.length() - 6);
+ }
if (type.cppName.endsWith("*")) {
type.indirections++;
if (type.reference) {
@@ -721,7 +725,7 @@ Type type(Context context, boolean definition) throws ParserException {
type.cppName = type.cppName.substring(0, type.cppName.length() - 1);
}
if (type.cppName.endsWith(" const")) {
- type.constPointer = true;
+ type.constValue = true;
type.cppName = type.cppName.substring(0, type.cppName.length() - 6);
}
@@ -729,7 +733,8 @@ Type type(Context context, boolean definition) throws ParserException {
String shortName = type.cppName;
String[] names = context.qualify(type.cppName);
if (definition && names.length > 0) {
- String constName = type.constValue || type.constPointer ? "const " + names[0] : names[0];
+ String constName = type.constValue ? "const " + names[0] : names[0];
+ constName = type.constPointer ? constName + " const" : constName;
info = infoMap.getFirst(constName, false);
type.cppName = names[0];
} else {
@@ -745,7 +750,8 @@ Type type(Context context, boolean definition) throws ParserException {
// skip, we would probably get Info for the constructors, not the type
continue;
}
- String constName = type.constValue || type.constPointer ? "const " + name : name;
+ String constName = type.constValue ? "const " + name : name;
+ constName = type.constPointer ? constName + " const" : constName;
if ((info = infoMap.getFirst(constName, false)) != null) {
type.cppName = name;
break;
@@ -765,6 +771,10 @@ Type type(Context context, boolean definition) throws ParserException {
type.constValue = true;
type.cppName = type.cppName.substring(6);
}
+ if (type.cppName.endsWith(" const")) {
+ type.constPointer = true;
+ type.cppName = type.cppName.substring(0, type.cppName.length() - 6);
+ }
if (type.cppName.endsWith("*")) {
type.indirections++;
if (type.reference) {
@@ -777,7 +787,7 @@ Type type(Context context, boolean definition) throws ParserException {
type.cppName = type.cppName.substring(0, type.cppName.length() - 1);
}
if (type.cppName.endsWith(" const")) {
- type.constPointer = true;
+ type.constValue = true;
type.cppName = type.cppName.substring(0, type.cppName.length() - 6);
}
@@ -1182,9 +1192,6 @@ Declarator declarator(Context context, String defaultName, int infoNumber, boole
if (type.constValue && !cast.startsWith("const ")) {
cast = "const " + cast;
}
- if (type.constPointer && !cast.endsWith(" const")) {
- cast = cast + " const";
- }
if (type.indirections > 0) {
dcl.indirections += type.indirections;
for (int i = 0; i < type.indirections; i++) {
@@ -1195,6 +1202,9 @@ Declarator declarator(Context context, String defaultName, int infoNumber, boole
dcl.reference = true;
cast += "&";
}
+ if (type.constPointer && !cast.endsWith(" const")) {
+ cast = cast + " const";
+ }
for (String s : info2.annotations) {
type.annotations += s + " ";
}
@@ -1245,10 +1255,12 @@ Declarator declarator(Context context, String defaultName, int infoNumber, boole
}
if (!needCast && !type.javaName.contains("@Cast")) {
- if (type.constValue && !implicitConst && !type.constPointer) {
+ if (type.constValue && !implicitConst) {
type.annotations = "@Const " + type.annotations;
- } else if (type.constPointer) {
- type.annotations = "@Const({" + type.constValue + ", " + type.constPointer + "}) " + type.annotations;
+ }
+ if (type.constPointer) {
+ // ignore, const pointers are not useful in generated code
+ // type.annotations = "@Const({" + type.constValue + ", " + type.constPointer + "}) " + type.annotations;
}
}
}
@@ -1371,6 +1383,13 @@ Declarator declarator(Context context, String defaultName, int infoNumber, boole
functionType = functionType.substring(functionType.lastIndexOf(' ') + 1); // get rid of pointer annotations
if (!functionType.equals("Pointer")) {
definition.type = new Type(functionType);
+ for (Info info2 : infoMap.get("function/pointers")) {
+ if (info2 != null && info2.annotations != null) {
+ for (String s : info2.annotations) {
+ definition.text += s + " ";
+ }
+ }
+ }
definition.text += (tokens.get().match(Token.CONST, Token.__CONST, Token.CONSTEXPR) ? "@Const " : "") +
"public static class " + functionType + " extends FunctionPointer {\n" +
" static { Loader.load(); }\n" +
@@ -1923,9 +1942,6 @@ boolean function(Context context, DeclarationList declList) throws ParserExcepti
if (d.type.constValue && !s.startsWith("const ")) {
s = "const " + s;
}
- if (d.type.constPointer && !s.endsWith(" const")) {
- s = s + " const";
- }
if (d.indirections > 0) {
for (int i = 0; i < d.indirections; i++) {
s += "*";
@@ -1936,6 +1952,9 @@ boolean function(Context context, DeclarationList declList) throws ParserExcepti
s += "&";
s2 += "&";
}
+ if (d.type.constPointer && !s.endsWith(" const")) {
+ s = s + " const";
+ }
fullname += separator + s;
fullname2 += separator + s2;
separator = ", ";
@@ -2264,12 +2283,12 @@ boolean variable(Context context, DeclarationList declList) throws ParserExcepti
dcl.type.annotations = dcl.type.annotations.replaceAll("@Name\\(.*\\) ", "");
javaName = metadcl.javaName + "_" + shortName;
}
- if (dcl.type.constValue || dcl.constPointer) {
+ if ((dcl.type.constValue && dcl.indirections == 0) || dcl.constPointer) {
decl.text += "@MemberGetter ";
}
decl.text += modifiers + dcl.type.annotations.replace("@ByVal ", "@ByRef ")
+ dcl.type.javaName + " " + javaName + "(" + indices + ");";
- if (!dcl.type.constValue && !dcl.constPointer) {
+ if (!(dcl.type.constValue && dcl.indirections == 0) && !dcl.constPointer) {
if (indices.length() > 0) {
indices += ", ";
}
@@ -2650,9 +2669,6 @@ boolean typedef(Context context, DeclarationList declList) throws ParserExceptio
if (dcl.type.constValue && !s.startsWith("const ")) {
s = "const " + s;
}
- if (dcl.type.constPointer && !s.endsWith(" const")) {
- s = s + " const";
- }
if (dcl.type.indirections > 0) {
for (int i = 0; i < dcl.type.indirections; i++) {
s += "*";
@@ -2661,6 +2677,9 @@ boolean typedef(Context context, DeclarationList declList) throws ParserExceptio
if (dcl.type.reference) {
s += "&";
}
+ if (dcl.type.constPointer && !s.endsWith(" const")) {
+ s = s + " const";
+ }
info.cppNames(defName, s).cppTypes(s);
}
if (info.valueTypes == null && dcl.indirections > 0) {
@@ -3498,9 +3517,6 @@ void declarations(Context context, DeclarationList declList) throws ParserExcept
if (t.constValue && !s.startsWith("const ")) {
s = "const " + s;
}
- if (t.constPointer && !s.endsWith(" const")) {
- s = s + " const";
- }
if (t.indirections > 0) {
for (int i = 0; i < t.indirections; i++) {
s += "*";
@@ -3509,6 +3525,9 @@ void declarations(Context context, DeclarationList declList) throws ParserExcept
if (t.reference) {
s += "&";
}
+ if (t.constPointer && !s.endsWith(" const")) {
+ s = s + " const";
+ }
t.cppName = s;
e.setValue(t);
}
diff --git a/src/test/java/org/bytedeco/javacpp/PointerTest.java b/src/test/java/org/bytedeco/javacpp/PointerTest.java
index 70935b639..683d9dcb1 100644
--- a/src/test/java/org/bytedeco/javacpp/PointerTest.java
+++ b/src/test/java/org/bytedeco/javacpp/PointerTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016-2018 Samuel Audet
+ * Copyright (C) 2016-2019 Samuel Audet
*
* Licensed either under the Apache License, Version 2.0, or (at your option)
* under the terms of the GNU General Public License as published by
@@ -33,6 +33,7 @@
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
+import org.bytedeco.javacpp.annotation.Allocator;
import org.bytedeco.javacpp.annotation.Platform;
import org.bytedeco.javacpp.tools.Builder;
import org.junit.BeforeClass;
@@ -47,8 +48,10 @@
@Platform(define = {"NATIVE_ALLOCATOR malloc", "NATIVE_DEALLOCATOR free"})
public class PointerTest {
- static long maxBytes = 1024 * 1024 * 1024; /* 1g */
+ static final int allocatorMax = 11;
+ static final long maxBytes = 1024 * 1024 * 1024; /* 1g */
+ @Allocator(max = allocatorMax)
static class TestFunction extends FunctionPointer {
public TestFunction(Pointer p) { super(p); }
public TestFunction() { allocate(); }
@@ -67,12 +70,6 @@ static class TestFunction extends FunctionPointer {
System.out.println("Loader");
Loader.load(c);
- Pointer address = Loader.addressof("strlen");
- assertNotNull(address);
- TestFunction function = new TestFunction().put(address);
- assertEquals(address, function.get());
- assertEquals(5, function.call("12345"));
-
int totalProcessors = Loader.totalProcessors();
int totalCores = Loader.totalCores();
int totalChips = Loader.totalChips();
@@ -84,6 +81,45 @@ static class TestFunction extends FunctionPointer {
assertNotEquals(null, Loader.getJavaVM());
}
+ @Test public void testFunctionPointer() {
+ System.out.println("FunctionPointer");
+
+ Pointer address = Loader.addressof("strlen");
+ assertNotNull(address);
+ TestFunction function = new TestFunction().put(address);
+ assertEquals(address, function.get());
+ assertEquals(5, function.call("12345"));
+ function.deallocate();
+
+ TestFunction[] functions = new TestFunction[allocatorMax];
+ Pointer prevp = new Pointer();
+ for (int i = 0; i < allocatorMax; i++) {
+ final int n = i;
+ functions[i] = new TestFunction() {
+ @Override public int call(String s) { return n; }
+ };
+ Pointer p = functions[i].get();
+ System.out.println(p);
+ assertNotNull(p);
+ assertNotEquals(prevp, p);
+ prevp = p;
+ }
+
+ TestFunction f = new TestFunction() {
+ @Override public int call(String s) { return allocatorMax; }
+ };
+ assertNull(f.get());
+
+ for (int i = 0; i < allocatorMax; i++) {
+ functions[i].deallocate();
+ }
+
+ TestFunction f2 = new TestFunction() {
+ @Override public int call(String s) { return allocatorMax; }
+ };
+ assertNotNull(f2.get());
+ }
+
static Object fieldReference;
@Test public void testPointer() {