Skip to content

Commit

Permalink
* Fix Parser incorrectly shortening type names for nested class te…
Browse files Browse the repository at this point in the history
…mplate instances

 * Make `Parser` output `boolean has_value()` methods for basic containers like `std::optional`
 * Add `OptionalAdapter` and corresponding `@Optional` annotation for containers like `std::optional`
  • Loading branch information
saudet committed Mar 15, 2022
1 parent 9a57b0d commit cd47d1d
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 9 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@

* Fix `Parser` incorrectly shortening type names for nested class template instances
* Make `Parser` output `boolean has_value()` methods for basic containers like `std::optional`
* Add `OptionalAdapter` and corresponding `@Optional` annotation for containers like `std::optional`
* Switch to `AttachCurrentThreadAsDaemon()` when attaching native threads on callback ([pull #561](https://github.com/bytedeco/javacpp/pull/561))
* Add to `InfoMap` default pointer and value types for integer types in `std::` namespace
* Fix Android build properties for NDK r23b
Expand Down
28 changes: 28 additions & 0 deletions src/main/java/org/bytedeco/javacpp/annotation/Optional.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.bytedeco.javacpp.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.bytedeco.javacpp.Pointer;
import org.bytedeco.javacpp.tools.Generator;

/**
* A shorthand for {@code @Adapter("OptionalAdapter<type>")}.
* We also need to define the {@code OPTIONAL_NAMESPACE} macro
* to something like {@code boost} or {@code std}.
*
* @see Adapter
* @see Generator
*
* @author Samuel Audet
*/
@Documented @Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.PARAMETER})
@Adapter("OptionalAdapter")
public @interface Optional {
/** The template type of {@code OptionalAdapter}. If not specified, it is
* inferred from the value type of the {@link Pointer} or Java array. */
String value() default "";
}
32 changes: 32 additions & 0 deletions src/main/java/org/bytedeco/javacpp/tools/Generator.java
Original file line number Diff line number Diff line change
Expand Up @@ -1392,6 +1392,38 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver
out.println("};");
out.println("#endif");
out.println();
out.println("#ifdef OPTIONAL_NAMESPACE");
out.println("template<class T> class OptionalAdapter {");
out.println("public:");
out.println(" typedef OPTIONAL_NAMESPACE::optional<T> O;");
out.println(" OptionalAdapter(const T* ptr, size_t size, void* owner) : ptr((T*)ptr), size(size), owner(owner),");
out.println(" optional2(owner != NULL && owner != ptr ? *(O*)owner : (ptr ? O(*(T*)ptr) : O())), optional(optional2) { }");
out.println(" OptionalAdapter(const O& optional) : ptr(0), size(0), owner(0), optional2(optional), optional(optional2) { }");
out.println(" OptionalAdapter( O& optional) : ptr(0), size(0), owner(0), optional(optional) { }");
out.println(" OptionalAdapter(const O* optional) : ptr(0), size(0), owner(0), optional(*(O*)optional) { }");
out.println(" void assign(T* ptr, size_t size, void* owner) {");
out.println(" this->ptr = ptr;");
out.println(" this->size = size;");
out.println(" this->owner = owner;");
out.println(" this->optional = owner != NULL && owner != ptr ? *(O*)owner : (ptr ? O(*(T*)ptr) : O());");
out.println(" }");
out.println(" static void deallocate(void* owner) { delete (O*)owner; }");
out.println(" operator typename OPTIONAL_NAMESPACE::remove_const<T>::type*() {");
out.println(" if (owner == NULL || owner == ptr) {");
out.println(" owner = new O(optional);");
out.println(" }");
out.println(" ptr = (*(O*)owner).has_value() ? (*(O*)owner).operator->() : NULL;");
out.println(" return (typename OPTIONAL_NAMESPACE::remove_const<T>::type*)ptr;");
out.println(" }");
out.println(" operator O&() { return optional; }");
out.println(" operator O*() { return &optional; }");
out.println(" T* ptr;");
out.println(" size_t size;");
out.println(" void* owner;");
out.println(" O optional2;");
out.println(" O& optional;");
out.println("};");
out.println("#endif");
}
if (!functions.isEmpty() || !virtualFunctions.isEmpty()) {
out.println("#if !defined(NO_JNI_DETACH_THREAD) && (defined(__linux__) || defined(__APPLE__))");
Expand Down
7 changes: 5 additions & 2 deletions src/main/java/org/bytedeco/javacpp/tools/InfoMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,10 @@ public class InfoMap extends HashMap<String,List<Info>> {
.put(new Info(" __attribute__", "__declspec", "static_assert").annotations().skip())
.put(new Info("void").valueTypes("void").pointerTypes("Pointer"))
.put(new Info("std::nullptr_t").valueTypes("Pointer").pointerTypes("PointerPointer"))
.put(new Info("FILE", "time_t", "va_list", "std::exception", "std::istream", "std::ostream", "std::iostream",
"std::ifstream", "std::ofstream", "std::fstream", "std::stringstream").cast().pointerTypes("Pointer"))
.put(new Info("FILE", "time_t", "va_list", "std::exception",
"std::istream", "std::ostream", "std::iostream",
"std::ifstream", "std::ofstream", "std::fstream",
"std::istringstream", "std::ostringstream", "std::stringstream").cast().pointerTypes("Pointer"))

.put(new Info("std::int8_t", "int8_t", "__int8", "jbyte", "signed char")
.valueTypes("byte").pointerTypes("BytePointer", "ByteBuffer", "byte[]"))
Expand Down Expand Up @@ -97,6 +99,7 @@ public class InfoMap extends HashMap<String,List<Info>> {
.put(new Info("std::char32_t", "char32_t").cast().valueTypes("int").pointerTypes("IntPointer", "int[]"))
.put(new Info("std::wchar_t", "wchar_t", "WCHAR").cast().valueTypes("char", "int").pointerTypes("CharPointer", "IntPointer"))
.put(new Info("const char").valueTypes("@Cast(\"const char\") byte").pointerTypes("@Cast(\"const char*\") BytePointer", "String"))
.put(new Info("boost::optional", "std::optional").annotations("@Optional"))
.put(new Info("boost::shared_ptr", "std::shared_ptr").annotations("@SharedPtr"))
.put(new Info("boost::movelib::unique_ptr", "std::unique_ptr").annotations("@UniquePtr"))
.put(new Info("std::string").annotations("@StdString").valueTypes("BytePointer", "String").pointerTypes("BytePointer"))
Expand Down
20 changes: 14 additions & 6 deletions src/main/java/org/bytedeco/javacpp/tools/Parser.java
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,7 @@ void containers(Context context, DeclarationList declList) throws ParserExceptio
for (Type type : containerType.arguments) {
if (containerType.arguments.length == 1 && !tuple) {
decl.text += "\n"
+ " public native boolean has_value();\n"
+ " @Name(\"value\") public native " + type.annotations + type.javaName + " get();\n";
} else {
int namespace = containerName.lastIndexOf("::");
Expand Down Expand Up @@ -606,6 +607,10 @@ Type[] templateArguments(Context context) throws ParserException {
count++;
} else if (token.match('>', ')')) {
count--;
if (tokens.get(1).match('<')) {
// probably an actual less than
tokens.next();
}
}
for (int i = 0; i < type.indirections; i++) {
// this is not actually a type -> add back the "*"
Expand Down Expand Up @@ -2203,9 +2208,10 @@ boolean function(Context context, DeclarationList declList) throws ParserExcepti
dcl.cppName = type.cppName;
dcl.javaName = type.javaName.substring(type.javaName.lastIndexOf(' ') + 1);
if (type.operator) {
String shortName = dcl.javaName.substring(dcl.javaName.lastIndexOf('.') + 1);
dcl.cppName = "operator " + (dcl.type.constValue ? "const " : "")
+ dcl.type.cppName + (dcl.type.indirections > 0 ? "*" : dcl.type.reference ? "&" : "");
dcl.javaName = "as" + Character.toUpperCase(dcl.javaName.charAt(0)) + dcl.javaName.substring(1);
dcl.javaName = "as" + Character.toUpperCase(shortName.charAt(0)) + shortName.substring(1);
}
dcl.signature = dcl.javaName + params.signature;
} else {
Expand Down Expand Up @@ -2367,9 +2373,10 @@ boolean function(Context context, DeclarationList declList) throws ParserExcepti
dcl.cppName = type.cppName;
dcl.javaName = type.javaName.substring(type.javaName.lastIndexOf(' ') + 1);
if (type.operator) {
String shortName = dcl.javaName.substring(dcl.javaName.lastIndexOf('.') + 1);
dcl.cppName = "operator " + (dcl.type.constValue ? "const " : "")
+ dcl.type.cppName + (dcl.type.indirections > 0 ? "*" : dcl.type.reference ? "&" : "");
dcl.javaName = "as" + Character.toUpperCase(dcl.javaName.charAt(0)) + dcl.javaName.substring(1);
dcl.javaName = "as" + Character.toUpperCase(shortName.charAt(0)) + shortName.substring(1);
}
dcl.signature = dcl.javaName + params.signature;
for (Token token = tokens.get(); !token.match(Token.EOF); token = tokens.get()) {
Expand Down Expand Up @@ -3349,9 +3356,10 @@ boolean group(Context context, DeclarationList declList) throws ParserException
if (baseClasses.size() > 0) {
for (Type t : baseClasses) {
if (!t.javaName.equals("Pointer")) {
casts += " public " + t.javaName + " as" + t.javaName + "() { return as" + t.javaName + "(this); }\n"
String shortName = t.javaName.substring(t.javaName.lastIndexOf('.') + 1);
casts += " public " + t.javaName + " as" + shortName + "() { return as" + shortName + "(this); }\n"
+ " @Namespace public static native @Name(\"static_cast<" + t.cppName + "*>\") "
+ t.javaName + " as" + t.javaName + "(" + type.javaName + " pointer);\n";
+ t.javaName + " as" + shortName + "(" + type.javaName + " pointer);\n";
}
}
}
Expand Down Expand Up @@ -3385,7 +3393,7 @@ boolean group(Context context, DeclarationList declList) throws ParserException
return true;
}
if (!fullName.equals(cppName)) {
decl.text += "@Name(\"" + (context.javaName == null || namespace < 0 ? cppName : cppName.substring(namespace + 2)) + "\") ";
decl.text += "@Name(\"" + (context.javaName == null || context.namespace == null ? cppName : cppName.substring(context.namespace.length() + 2)) + "\") ";
} else if (context.namespace != null && context.javaName == null) {
decl.text += "@Namespace(\"" + context.namespace + "\") ";
}
Expand Down Expand Up @@ -3505,7 +3513,7 @@ boolean group(Context context, DeclarationList declList) throws ParserException
}
if (!anonymous) {
if (!fullName.equals(cppName)) {
decl.text += "@Name(\"" + (context.javaName == null || namespace < 0 ? cppName : cppName.substring(namespace + 2)) + "\") ";
decl.text += "@Name(\"" + (context.javaName == null || context.namespace == null ? cppName : cppName.substring(context.namespace.length() + 2)) + "\") ";
} else if (context.namespace != null && context.javaName == null) {
decl.text += "@Namespace(\"" + context.namespace + "\") ";
}
Expand Down
12 changes: 11 additions & 1 deletion src/test/java/org/bytedeco/javacpp/AdapterTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.bytedeco.javacpp.annotation.Cast;
import org.bytedeco.javacpp.annotation.Const;
import org.bytedeco.javacpp.annotation.Function;
import org.bytedeco.javacpp.annotation.Optional;
import org.bytedeco.javacpp.annotation.Platform;
import org.bytedeco.javacpp.annotation.SharedPtr;
import org.bytedeco.javacpp.annotation.StdBasicString;
Expand All @@ -48,7 +49,7 @@
*
* @author Samuel Audet
*/
@Platform(compiler = "cpp11", define = {"SHARED_PTR_NAMESPACE std", "UNIQUE_PTR_NAMESPACE std"}, include = "AdapterTest.h")
@Platform(compiler = "cpp17", define = {"OPTIONAL_NAMESPACE std", "SHARED_PTR_NAMESPACE std", "UNIQUE_PTR_NAMESPACE std"}, include = "AdapterTest.h")
public class AdapterTest {

static native @StdString String testStdString(@StdString String str);
Expand Down Expand Up @@ -122,6 +123,8 @@ static class MovedData extends Pointer {
static native @StdMove MovedData getMovedData();
static native void putMovedData(@StdMove MovedData m);

static native @Optional IntPointer testOptionalInt(@Optional IntPointer o);

@BeforeClass public static void setUpClass() throws Exception {
System.out.println("Builder");
Class c = AdapterTest.class;
Expand Down Expand Up @@ -325,4 +328,11 @@ static class MovedData extends Pointer {
m.deallocate();
m2.deallocate();
}

@Test public void testOptional() {
System.out.println("Optional");
assertTrue(testOptionalInt(new IntPointer((Pointer)null)).isNull());
assertEquals(42, testOptionalInt(new IntPointer(1).put(42)).get(0));
}

}
5 changes: 5 additions & 0 deletions src/test/resources/org/bytedeco/javacpp/AdapterTest.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <memory>
#include <string>
#include <vector>
#include <optional>

std::string testStdString(std::string str) {
return str;
Expand Down Expand Up @@ -132,3 +133,7 @@ MovedData&& getMovedData() {
void putMovedData(MovedData&& m) {
movedData = m;
}

std::optional<int> testOptionalInt(std::optional<int> o) {
return o;
}

0 comments on commit cd47d1d

Please sign in to comment.