Skip to content

Commit cfcee03

Browse files
committed
* Support multiple instances of FunctionPointer subclasses, up to the value in @Allocator(max=...) (issue bytedeco/javacpp-presets#683)
1 parent 1bc3afe commit cfcee03

File tree

7 files changed

+199
-83
lines changed

7 files changed

+199
-83
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11

2+
* 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))
23
* Allow suffixing library names with `:` to specify exact relative paths to libraries, ignoring any additional prefix or suffix
34
* Prevent `Loader.load()` from trying to load library files that do not exist or to create symbolic links to them
45
* Let `Loader.load()` extract libraries suffixed with `##`, but still ignored for copying by `Builder`

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
JavaCPP
22
=======
33

4-
[![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)
4+
[![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)
55

66

77
Introduction

src/main/java/org/bytedeco/javacpp/annotation/Allocator.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import java.lang.annotation.Retention;
66
import java.lang.annotation.RetentionPolicy;
77
import java.lang.annotation.Target;
8+
import org.bytedeco.javacpp.FunctionPointer;
89
import org.bytedeco.javacpp.Pointer;
910
import org.bytedeco.javacpp.tools.Generator;
1011

@@ -20,12 +21,18 @@
2021
* the given arguments, and initializes the {@link Pointer#address} as well as
2122
* the {@link Pointer#deallocator} with {@code NativeDeallocator}, based on the
2223
* {@code delete} operator, if not additionally annotated with {@link NoDeallocator}.
24+
* <p>
25+
* Can also be used on classes to set the {@link #max} value for enclosed function pointers.
2326
*
2427
* @see Pointer#init(long, long, long, long)
2528
* @see Generator
2629
*
2730
* @author Samuel Audet
2831
*/
2932
@Documented @Retention(RetentionPolicy.RUNTIME)
30-
@Target({ElementType.METHOD})
31-
public @interface Allocator { }
33+
@Target({ElementType.TYPE, ElementType.METHOD})
34+
public @interface Allocator {
35+
/** The maximum number of instances that can be allocated in the case of a {@link FunctionPointer} subclass.
36+
* Does not affect the underlying function object or other {@link Pointer} which have no such allocation limits. */
37+
int max() default 10;
38+
}

src/main/java/org/bytedeco/javacpp/tools/Generator.java

Lines changed: 96 additions & 43 deletions
Large diffs are not rendered by default.

src/main/java/org/bytedeco/javacpp/tools/MethodInformation.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public class MethodInformation {
3636
int modifiers;
3737
Class<?> returnType;
3838
String name, memberName[];
39-
int dim;
39+
int allocatorMax, dim;
4040
boolean[] parameterRaw;
4141
Class<?>[] parameterTypes;
4242
Annotation[][] parameterAnnotations;

src/main/java/org/bytedeco/javacpp/tools/Parser.java

Lines changed: 47 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2013-2018 Samuel Audet
2+
* Copyright (C) 2013-2019 Samuel Audet
33
*
44
* Licensed either under the Apache License, Version 2.0, or (at your option)
55
* under the terms of the GNU General Public License as published by
@@ -207,9 +207,6 @@ void containers(Context context, DeclarationList declList) throws ParserExceptio
207207
if (valueType.constValue && !cast.startsWith("const ")) {
208208
cast = "const " + cast;
209209
}
210-
if (valueType.constPointer && !cast.endsWith(" const")) {
211-
cast = cast + " const";
212-
}
213210
if (valueType.indirections > 0) {
214211
for (int i = 0; i < valueType.indirections; i++) {
215212
cast += "*";
@@ -220,6 +217,9 @@ void containers(Context context, DeclarationList declList) throws ParserExceptio
220217
if (valueType.reference) {
221218
cast += "&";
222219
}
220+
if (valueType.constPointer && !cast.endsWith(" const")) {
221+
cast = cast + " const";
222+
}
223223
valueType.annotations = "@Cast(\"" + cast + "\") " + valueType.annotations;
224224
}
225225
String arrayBrackets = "";
@@ -564,15 +564,15 @@ Type type(Context context, boolean definition) throws ParserException {
564564
if (t.constValue && !s.startsWith("const ")) {
565565
s = "const " + s;
566566
}
567-
if (t.constPointer && !s.endsWith(" const")) {
568-
s = s + " const";
569-
}
570567
for (int i = 0; i < t.indirections; i++) {
571568
s += "*";
572569
}
573570
if (t.reference) {
574571
s += "&";
575572
}
573+
if (t.constPointer && !s.endsWith(" const")) {
574+
s = s + " const";
575+
}
576576
type.cppName += s;
577577
separator = ",";
578578
}
@@ -709,6 +709,10 @@ Type type(Context context, boolean definition) throws ParserException {
709709
type.constValue = true;
710710
type.cppName = type.cppName.substring(6);
711711
}
712+
if (type.cppName.endsWith(" const")) {
713+
type.constPointer = true;
714+
type.cppName = type.cppName.substring(0, type.cppName.length() - 6);
715+
}
712716
if (type.cppName.endsWith("*")) {
713717
type.indirections++;
714718
if (type.reference) {
@@ -721,15 +725,16 @@ Type type(Context context, boolean definition) throws ParserException {
721725
type.cppName = type.cppName.substring(0, type.cppName.length() - 1);
722726
}
723727
if (type.cppName.endsWith(" const")) {
724-
type.constPointer = true;
728+
type.constValue = true;
725729
type.cppName = type.cppName.substring(0, type.cppName.length() - 6);
726730
}
727731

728732
Info info = null;
729733
String shortName = type.cppName;
730734
String[] names = context.qualify(type.cppName);
731735
if (definition && names.length > 0) {
732-
String constName = type.constValue || type.constPointer ? "const " + names[0] : names[0];
736+
String constName = type.constValue ? "const " + names[0] : names[0];
737+
constName = type.constPointer ? constName + " const" : constName;
733738
info = infoMap.getFirst(constName, false);
734739
type.cppName = names[0];
735740
} else {
@@ -745,7 +750,8 @@ Type type(Context context, boolean definition) throws ParserException {
745750
// skip, we would probably get Info for the constructors, not the type
746751
continue;
747752
}
748-
String constName = type.constValue || type.constPointer ? "const " + name : name;
753+
String constName = type.constValue ? "const " + name : name;
754+
constName = type.constPointer ? constName + " const" : constName;
749755
if ((info = infoMap.getFirst(constName, false)) != null) {
750756
type.cppName = name;
751757
break;
@@ -765,6 +771,10 @@ Type type(Context context, boolean definition) throws ParserException {
765771
type.constValue = true;
766772
type.cppName = type.cppName.substring(6);
767773
}
774+
if (type.cppName.endsWith(" const")) {
775+
type.constPointer = true;
776+
type.cppName = type.cppName.substring(0, type.cppName.length() - 6);
777+
}
768778
if (type.cppName.endsWith("*")) {
769779
type.indirections++;
770780
if (type.reference) {
@@ -777,7 +787,7 @@ Type type(Context context, boolean definition) throws ParserException {
777787
type.cppName = type.cppName.substring(0, type.cppName.length() - 1);
778788
}
779789
if (type.cppName.endsWith(" const")) {
780-
type.constPointer = true;
790+
type.constValue = true;
781791
type.cppName = type.cppName.substring(0, type.cppName.length() - 6);
782792
}
783793

@@ -1182,9 +1192,6 @@ Declarator declarator(Context context, String defaultName, int infoNumber, boole
11821192
if (type.constValue && !cast.startsWith("const ")) {
11831193
cast = "const " + cast;
11841194
}
1185-
if (type.constPointer && !cast.endsWith(" const")) {
1186-
cast = cast + " const";
1187-
}
11881195
if (type.indirections > 0) {
11891196
dcl.indirections += type.indirections;
11901197
for (int i = 0; i < type.indirections; i++) {
@@ -1195,6 +1202,9 @@ Declarator declarator(Context context, String defaultName, int infoNumber, boole
11951202
dcl.reference = true;
11961203
cast += "&";
11971204
}
1205+
if (type.constPointer && !cast.endsWith(" const")) {
1206+
cast = cast + " const";
1207+
}
11981208
for (String s : info2.annotations) {
11991209
type.annotations += s + " ";
12001210
}
@@ -1245,10 +1255,12 @@ Declarator declarator(Context context, String defaultName, int infoNumber, boole
12451255
}
12461256

12471257
if (!needCast && !type.javaName.contains("@Cast")) {
1248-
if (type.constValue && !implicitConst && !type.constPointer) {
1258+
if (type.constValue && !implicitConst) {
12491259
type.annotations = "@Const " + type.annotations;
1250-
} else if (type.constPointer) {
1251-
type.annotations = "@Const({" + type.constValue + ", " + type.constPointer + "}) " + type.annotations;
1260+
}
1261+
if (type.constPointer) {
1262+
// ignore, const pointers are not useful in generated code
1263+
// type.annotations = "@Const({" + type.constValue + ", " + type.constPointer + "}) " + type.annotations;
12521264
}
12531265
}
12541266
}
@@ -1371,6 +1383,13 @@ Declarator declarator(Context context, String defaultName, int infoNumber, boole
13711383
functionType = functionType.substring(functionType.lastIndexOf(' ') + 1); // get rid of pointer annotations
13721384
if (!functionType.equals("Pointer")) {
13731385
definition.type = new Type(functionType);
1386+
for (Info info2 : infoMap.get("function/pointers")) {
1387+
if (info2 != null && info2.annotations != null) {
1388+
for (String s : info2.annotations) {
1389+
definition.text += s + " ";
1390+
}
1391+
}
1392+
}
13741393
definition.text += (tokens.get().match(Token.CONST, Token.__CONST, Token.CONSTEXPR) ? "@Const " : "") +
13751394
"public static class " + functionType + " extends FunctionPointer {\n" +
13761395
" static { Loader.load(); }\n" +
@@ -1923,9 +1942,6 @@ boolean function(Context context, DeclarationList declList) throws ParserExcepti
19231942
if (d.type.constValue && !s.startsWith("const ")) {
19241943
s = "const " + s;
19251944
}
1926-
if (d.type.constPointer && !s.endsWith(" const")) {
1927-
s = s + " const";
1928-
}
19291945
if (d.indirections > 0) {
19301946
for (int i = 0; i < d.indirections; i++) {
19311947
s += "*";
@@ -1936,6 +1952,9 @@ boolean function(Context context, DeclarationList declList) throws ParserExcepti
19361952
s += "&";
19371953
s2 += "&";
19381954
}
1955+
if (d.type.constPointer && !s.endsWith(" const")) {
1956+
s = s + " const";
1957+
}
19391958
fullname += separator + s;
19401959
fullname2 += separator + s2;
19411960
separator = ", ";
@@ -2264,12 +2283,12 @@ boolean variable(Context context, DeclarationList declList) throws ParserExcepti
22642283
dcl.type.annotations = dcl.type.annotations.replaceAll("@Name\\(.*\\) ", "");
22652284
javaName = metadcl.javaName + "_" + shortName;
22662285
}
2267-
if (dcl.type.constValue || dcl.constPointer) {
2286+
if ((dcl.type.constValue && dcl.indirections == 0) || dcl.constPointer) {
22682287
decl.text += "@MemberGetter ";
22692288
}
22702289
decl.text += modifiers + dcl.type.annotations.replace("@ByVal ", "@ByRef ")
22712290
+ dcl.type.javaName + " " + javaName + "(" + indices + ");";
2272-
if (!dcl.type.constValue && !dcl.constPointer) {
2291+
if (!(dcl.type.constValue && dcl.indirections == 0) && !dcl.constPointer) {
22732292
if (indices.length() > 0) {
22742293
indices += ", ";
22752294
}
@@ -2650,9 +2669,6 @@ boolean typedef(Context context, DeclarationList declList) throws ParserExceptio
26502669
if (dcl.type.constValue && !s.startsWith("const ")) {
26512670
s = "const " + s;
26522671
}
2653-
if (dcl.type.constPointer && !s.endsWith(" const")) {
2654-
s = s + " const";
2655-
}
26562672
if (dcl.type.indirections > 0) {
26572673
for (int i = 0; i < dcl.type.indirections; i++) {
26582674
s += "*";
@@ -2661,6 +2677,9 @@ boolean typedef(Context context, DeclarationList declList) throws ParserExceptio
26612677
if (dcl.type.reference) {
26622678
s += "&";
26632679
}
2680+
if (dcl.type.constPointer && !s.endsWith(" const")) {
2681+
s = s + " const";
2682+
}
26642683
info.cppNames(defName, s).cppTypes(s);
26652684
}
26662685
if (info.valueTypes == null && dcl.indirections > 0) {
@@ -3498,9 +3517,6 @@ void declarations(Context context, DeclarationList declList) throws ParserExcept
34983517
if (t.constValue && !s.startsWith("const ")) {
34993518
s = "const " + s;
35003519
}
3501-
if (t.constPointer && !s.endsWith(" const")) {
3502-
s = s + " const";
3503-
}
35043520
if (t.indirections > 0) {
35053521
for (int i = 0; i < t.indirections; i++) {
35063522
s += "*";
@@ -3509,6 +3525,9 @@ void declarations(Context context, DeclarationList declList) throws ParserExcept
35093525
if (t.reference) {
35103526
s += "&";
35113527
}
3528+
if (t.constPointer && !s.endsWith(" const")) {
3529+
s = s + " const";
3530+
}
35123531
t.cppName = s;
35133532
e.setValue(t);
35143533
}

src/test/java/org/bytedeco/javacpp/PointerTest.java

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2016-2018 Samuel Audet
2+
* Copyright (C) 2016-2019 Samuel Audet
33
*
44
* Licensed either under the Apache License, Version 2.0, or (at your option)
55
* under the terms of the GNU General Public License as published by
@@ -33,6 +33,7 @@
3333
import java.util.concurrent.ExecutorService;
3434
import java.util.concurrent.Executors;
3535
import java.util.concurrent.TimeUnit;
36+
import org.bytedeco.javacpp.annotation.Allocator;
3637
import org.bytedeco.javacpp.annotation.Platform;
3738
import org.bytedeco.javacpp.tools.Builder;
3839
import org.junit.BeforeClass;
@@ -47,8 +48,10 @@
4748
@Platform(define = {"NATIVE_ALLOCATOR malloc", "NATIVE_DEALLOCATOR free"})
4849
public class PointerTest {
4950

50-
static long maxBytes = 1024 * 1024 * 1024; /* 1g */
51+
static final int allocatorMax = 11;
52+
static final long maxBytes = 1024 * 1024 * 1024; /* 1g */
5153

54+
@Allocator(max = allocatorMax)
5255
static class TestFunction extends FunctionPointer {
5356
public TestFunction(Pointer p) { super(p); }
5457
public TestFunction() { allocate(); }
@@ -67,12 +70,6 @@ static class TestFunction extends FunctionPointer {
6770
System.out.println("Loader");
6871
Loader.load(c);
6972

70-
Pointer address = Loader.addressof("strlen");
71-
assertNotNull(address);
72-
TestFunction function = new TestFunction().put(address);
73-
assertEquals(address, function.get());
74-
assertEquals(5, function.call("12345"));
75-
7673
int totalProcessors = Loader.totalProcessors();
7774
int totalCores = Loader.totalCores();
7875
int totalChips = Loader.totalChips();
@@ -84,6 +81,45 @@ static class TestFunction extends FunctionPointer {
8481
assertNotEquals(null, Loader.getJavaVM());
8582
}
8683

84+
@Test public void testFunctionPointer() {
85+
System.out.println("FunctionPointer");
86+
87+
Pointer address = Loader.addressof("strlen");
88+
assertNotNull(address);
89+
TestFunction function = new TestFunction().put(address);
90+
assertEquals(address, function.get());
91+
assertEquals(5, function.call("12345"));
92+
function.deallocate();
93+
94+
TestFunction[] functions = new TestFunction[allocatorMax];
95+
Pointer prevp = new Pointer();
96+
for (int i = 0; i < allocatorMax; i++) {
97+
final int n = i;
98+
functions[i] = new TestFunction() {
99+
@Override public int call(String s) { return n; }
100+
};
101+
Pointer p = functions[i].get();
102+
System.out.println(p);
103+
assertNotNull(p);
104+
assertNotEquals(prevp, p);
105+
prevp = p;
106+
}
107+
108+
TestFunction f = new TestFunction() {
109+
@Override public int call(String s) { return allocatorMax; }
110+
};
111+
assertNull(f.get());
112+
113+
for (int i = 0; i < allocatorMax; i++) {
114+
functions[i].deallocate();
115+
}
116+
117+
TestFunction f2 = new TestFunction() {
118+
@Override public int call(String s) { return allocatorMax; }
119+
};
120+
assertNotNull(f2.get());
121+
}
122+
87123
static Object fieldReference;
88124

89125
@Test public void testPointer() {

0 commit comments

Comments
 (0)