Skip to content

Commit

Permalink
* Support multiple instances of FunctionPointer subclasses, up to …
Browse files Browse the repository at this point in the history
…the value in `@Allocator(max=...)` (issue bytedeco/javacpp-presets#683)
  • Loading branch information
saudet committed May 12, 2019
1 parent 1bc3afe commit cfcee03
Show file tree
Hide file tree
Showing 7 changed files with 199 additions and 83 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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`
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
11 changes: 9 additions & 2 deletions src/main/java/org/bytedeco/javacpp/annotation/Allocator.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -20,12 +21,18 @@
* 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}.
* <p>
* 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
*
* @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;
}
139 changes: 96 additions & 43 deletions src/main/java/org/bytedeco/javacpp/tools/Generator.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
75 changes: 47 additions & 28 deletions src/main/java/org/bytedeco/javacpp/tools/Parser.java
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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 += "*";
Expand All @@ -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 = "";
Expand Down Expand Up @@ -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 = ",";
}
Expand Down Expand Up @@ -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) {
Expand All @@ -721,15 +725,16 @@ 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);
}

Info info = null;
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 {
Expand All @@ -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;
Expand All @@ -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) {
Expand All @@ -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);
}

Expand Down Expand Up @@ -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++) {
Expand All @@ -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 + " ";
}
Expand Down Expand Up @@ -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;
}
}
}
Expand Down Expand Up @@ -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" +
Expand Down Expand Up @@ -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 += "*";
Expand All @@ -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 = ", ";
Expand Down Expand Up @@ -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 += ", ";
}
Expand Down Expand Up @@ -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 += "*";
Expand All @@ -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) {
Expand Down Expand Up @@ -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 += "*";
Expand All @@ -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);
}
Expand Down
52 changes: 44 additions & 8 deletions src/test/java/org/bytedeco/javacpp/PointerTest.java
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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(); }
Expand All @@ -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();
Expand All @@ -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() {
Expand Down

0 comments on commit cfcee03

Please sign in to comment.