Skip to content

Commit

Permalink
* Add UniquePtrAdapter and corresponding @UniquePtr annotation t…
Browse files Browse the repository at this point in the history
…o support `unique_ptr` containers (issue bytedeco/javacpp-presets#266)
  • Loading branch information
saudet committed Aug 20, 2016
1 parent a394220 commit 8dcac09
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@

* Add `UniquePtrAdapter` and corresponding `@UniquePtr` annotation to support `unique_ptr` containers ([issue bytedeco/javacpp-presets#266](https://github.com/bytedeco/javacpp-presets/issues/266))
* Fix `Parser` not expecting `friend class` declarations that start with `::` ([pull #122](https://github.com/bytedeco/javacpp/issues/122))
* Synchronize memory allocation in `Pointer` to avoid `OutOfMemoryError` when low on memory
* Make it clear that `Indexable.createIndexer()` can throw a `NullPointerException` ([issue bytedeco/javacv#437](https://github.com/bytedeco/javacv/issues/437))
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Introduction
------------
JavaCPP provides efficient access to native C++ inside Java, not unlike the way some C/C++ compilers interact with assembly language. No need to invent new languages such as with [SWIG](http://www.swig.org/), [SIP](http://riverbankcomputing.co.uk/software/sip/), [C++/CLI](http://www.ecma-international.org/publications/standards/Ecma-372.htm), [Cython](http://www.cython.org/), or [RPython](https://pypi.python.org/pypi/rpython) as required by [cppyy](http://doc.pypy.org/en/latest/cppyy.html). Instead, it exploits the syntactic and semantic similarities between Java and C++. Under the hood, it uses JNI, so it works with all implementations of Java SE, in addition to [Android](http://www.android.com/), [Avian](https://readytalk.github.io/avian/), and [RoboVM](http://www.robovm.org/) ([instructions](#instructions-for-android-avian-and-robovm)).

More specifically, when compared to the approaches above or elsewhere ([CableSwig](http://www.itk.org/ITK/resources/CableSwig.html), [JNIGeneratorApp](http://www.eclipse.org/swt/jnigen.php), [cxxwrap](http://cxxwrap.sourceforge.net/), [JNIWrapper](http://www.teamdev.com/jniwrapper/), [Platform Invoke](https://msdn.microsoft.com/en-us/library/aa719485.aspx), [GlueGen](http://jogamp.org/gluegen/www/), [LWJGL Generator](https://github.com/LWJGL/lwjgl3-wiki/wiki/4.5.-The-Generator), [JNIDirect](http://web.archive.org/web/20050329122501/http://homepage.mac.com/pcbeard/JNIDirect/), [ctypes](http://docs.python.org/library/ctypes.html), [JNA](https://github.com/twall/jna), [JNIEasy](http://www.innowhere.com/jnieasy/), [JniMarshall](http://flinflon.brandonu.ca/Dueck/SystemsProgramming/JniMarshall/), [JNative](http://jnative.free.fr/), [J/Invoke](http://web.archive.org/web/20110727133817/http://www.jinvoke.com/), [HawtJNI](http://hawtjni.fusesource.org/), [JNR](https://github.com/jnr/), [BridJ](http://code.google.com/p/bridj/), [fficxx](http://ianwookim.org/fficxx/), etc.), it maps naturally and efficiently many common features afforded by the C++ language and often considered problematic, including overloaded operators, class and function templates, callbacks through function pointers, function objects (aka functors), virtual functions and member function pointers, nested struct definitions, variable length arguments, nested namespaces, large data structures containing arbitrary cycles, virtual and multiple inheritance, passing/returning by value/reference/string/vector, anonymous unions, bit fields, exceptions, destructors and shared pointers (via either try-with-resources or garbage collection), and documentation comments. Obviously, neatly supporting the whole of C++ would require more work (although one could argue about the intrinsic neatness of C++), but we are releasing it here as a proof of concept.
More specifically, when compared to the approaches above or elsewhere ([CableSwig](http://www.itk.org/ITK/resources/CableSwig.html), [JNIGeneratorApp](http://www.eclipse.org/swt/jnigen.php), [cxxwrap](http://cxxwrap.sourceforge.net/), [JNIWrapper](http://www.teamdev.com/jniwrapper/), [Platform Invoke](https://msdn.microsoft.com/en-us/library/aa719485.aspx), [GlueGen](http://jogamp.org/gluegen/www/), [LWJGL Generator](https://github.com/LWJGL/lwjgl3-wiki/wiki/4.5.-The-Generator), [JNIDirect](http://web.archive.org/web/20050329122501/http://homepage.mac.com/pcbeard/JNIDirect/), [ctypes](http://docs.python.org/library/ctypes.html), [JNA](https://github.com/twall/jna), [JNIEasy](http://www.innowhere.com/jnieasy/), [JniMarshall](http://flinflon.brandonu.ca/Dueck/SystemsProgramming/JniMarshall/), [JNative](http://jnative.free.fr/), [J/Invoke](http://web.archive.org/web/20110727133817/http://www.jinvoke.com/), [HawtJNI](http://hawtjni.fusesource.org/), [JNR](https://github.com/jnr/), [BridJ](http://code.google.com/p/bridj/), [fficxx](http://ianwookim.org/fficxx/), etc.), it maps naturally and efficiently many common features afforded by the C++ language and often considered problematic, including overloaded operators, class and function templates, callbacks through function pointers, function objects (aka functors), virtual functions and member function pointers, nested struct definitions, variable length arguments, nested namespaces, large data structures containing arbitrary cycles, virtual and multiple inheritance, passing/returning by value/reference/string/vector, anonymous unions, bit fields, exceptions, destructors and shared or unique pointers (via either try-with-resources or garbage collection), and documentation comments. Obviously, neatly supporting the whole of C++ would require more work (although one could argue about the intrinsic neatness of C++), but we are releasing it here as a proof of concept.

As a case in point, we have already used it to produce complete interfaces to OpenCV, FFmpeg, libdc1394, PGR FlyCapture, OpenKinect, videoInput, ARToolKitPlus, and others as part of the [JavaCPP Presets](https://github.com/bytedeco/javacpp-presets) subproject, also demonstrating early parsing capabilities of C/C++ header files that show promising and useful results.

Expand Down
28 changes: 28 additions & 0 deletions src/main/java/org/bytedeco/javacpp/annotation/UniquePtr.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("UniquePtrAdapter<type>")}.
* We also need to define the {@code UNIQUE_PTR_NAMESPACE} macro
* to something like {@code boost::movelib} or {@code std}.
*
* @see Adapter
* @see Generator
*
* @author Samuel Audet
*/
@Documented @Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.PARAMETER})
@Adapter("UniquePtrAdapter")
public @interface UniquePtr {
/** The template type of {@code UniquePtrAdapter}. If not specified, it is
* inferred from the value type of the {@link Pointer} or Java array. */
String value() default "";
}
39 changes: 37 additions & 2 deletions src/main/java/org/bytedeco/javacpp/tools/Generator.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
import java.nio.LongBuffer;
import java.nio.ShortBuffer;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Deque;
import java.util.HashMap;
Expand Down Expand Up @@ -684,6 +683,7 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver
out.println(" sharedPtr2(owner != NULL && owner != ptr ? *(S*)owner : S((T*)ptr)), sharedPtr(sharedPtr2) { }");
out.println(" SharedPtrAdapter(const S& sharedPtr) : ptr(0), size(0), owner(0), sharedPtr2(sharedPtr), sharedPtr(sharedPtr2) { }");
out.println(" SharedPtrAdapter( S& sharedPtr) : ptr(0), size(0), owner(0), sharedPtr(sharedPtr) { }");
out.println(" SharedPtrAdapter(const S* sharedPtr) : ptr(0), size(0), owner(0), sharedPtr(*(S*)sharedPtr) { }");
out.println(" void assign(T* ptr, size_t size, S* owner) {");
out.println(" this->ptr = ptr;");
out.println(" this->size = size;");
Expand All @@ -700,7 +700,7 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver
out.println(" }");
out.println(" operator const T*() { return sharedPtr.get(); }");
out.println(" operator S&() { return sharedPtr; }");
out.println(" operator S*() { return ptr ? &sharedPtr : 0; }");
out.println(" operator S*() { return &sharedPtr; }");
out.println(" T* ptr;");
out.println(" size_t size;");
out.println(" void* owner;");
Expand All @@ -709,6 +709,41 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver
out.println("};");
out.println("#endif");
out.println();
out.println("#ifdef UNIQUE_PTR_NAMESPACE");
out.println("template<class T> class UniquePtrAdapter {");
out.println("public:");
out.println(" typedef UNIQUE_PTR_NAMESPACE::unique_ptr<T> U;");
out.println(" UniquePtrAdapter(const T* ptr, size_t size, void* owner) : ptr((T*)ptr), size(size), owner(owner),");
out.println(" uniquePtr2(owner != NULL && owner != ptr ? U() : U((T*)ptr)),");
out.println(" uniquePtr(owner != NULL && owner != ptr ? *(U*)owner : uniquePtr2) { }");
out.println(" UniquePtrAdapter(const U& uniquePtr) : ptr(0), size(0), owner(0), uniquePtr((U&)uniquePtr) { }");
out.println(" UniquePtrAdapter( U& uniquePtr) : ptr(0), size(0), owner(0), uniquePtr(uniquePtr) { }");
out.println(" UniquePtrAdapter(const U* uniquePtr) : ptr(0), size(0), owner(0), uniquePtr(*(U*)uniquePtr) { }");
out.println(" void assign(T* ptr, size_t size, U* owner) {");
out.println(" this->ptr = ptr;");
out.println(" this->size = size;");
out.println(" this->owner = owner;");
out.println(" this->uniquePtr = owner != NULL && owner != ptr ? *(U*)owner : U((T*)ptr);");
out.println(" }");
out.println(" static void deallocate(void* owner) { delete (U*)owner; }");
out.println(" operator T*() {");
out.println(" ptr = uniquePtr.get();");
out.println(" if (owner == NULL || owner == ptr) {");
out.println(" owner = new U(UNIQUE_PTR_NAMESPACE::move(uniquePtr));");
out.println(" }");
out.println(" return ptr;");
out.println(" }");
out.println(" operator const T*() { return uniquePtr.get(); }");
out.println(" operator U&() { return uniquePtr; }");
out.println(" operator U*() { return &uniquePtr; }");
out.println(" T* ptr;");
out.println(" size_t size;");
out.println(" void* owner;");
out.println(" U uniquePtr2;");
out.println(" U& uniquePtr;");
out.println("};");
out.println("#endif");
out.println();
}
if (!functions.isEmpty() || !virtualFunctions.isEmpty()) {
out.println("static JavaCPP_noinline void JavaCPP_detach(bool detach) {");
Expand Down
1 change: 1 addition & 0 deletions src/main/java/org/bytedeco/javacpp/tools/InfoMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ public class InfoMap extends HashMap<String,List<Info>> {
.put(new Info("wchar_t", "WCHAR").cast().valueTypes("char").pointerTypes("CharPointer"))
.put(new Info("const char").valueTypes("byte").pointerTypes("@Cast(\"const char*\") BytePointer", "String"))
.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"))
.put(new Info("std::vector").annotations("@StdVector"))

Expand Down
34 changes: 33 additions & 1 deletion src/test/java/org/bytedeco/javacpp/AdapterTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@
import java.io.File;
import java.nio.IntBuffer;
import org.bytedeco.javacpp.annotation.Cast;
import org.bytedeco.javacpp.annotation.Const;
import org.bytedeco.javacpp.annotation.Platform;
import org.bytedeco.javacpp.annotation.SharedPtr;
import org.bytedeco.javacpp.annotation.StdString;
import org.bytedeco.javacpp.annotation.StdVector;
import org.bytedeco.javacpp.annotation.UniquePtr;
import org.bytedeco.javacpp.tools.Builder;
import org.junit.BeforeClass;
import org.junit.Test;
Expand All @@ -38,7 +40,7 @@
*
* @author Samuel Audet
*/
@Platform(compiler="cpp11", define="SHARED_PTR_NAMESPACE std", include="AdapterTest.h")
@Platform(compiler = "cpp11", define = {"SHARED_PTR_NAMESPACE std", "UNIQUE_PTR_NAMESPACE std"}, include = "AdapterTest.h")
public class AdapterTest {

static native @StdString String testStdString(@StdString String str);
Expand All @@ -52,6 +54,7 @@ public class AdapterTest {
static native IntPointer testIntString(IntPointer str);

static class SharedData extends Pointer {
SharedData(Pointer p) { super(p); }
SharedData(int data) { allocate(data); }
native void allocate(int data);

Expand All @@ -62,6 +65,18 @@ static class SharedData extends Pointer {
static native void storeSharedData(@SharedPtr SharedData s);
static native @SharedPtr SharedData fetchSharedData();

static class UniqueData extends Pointer {
UniqueData(Pointer p) { super(p); }
UniqueData(int data) { allocate(data); }
native void allocate(int data);

native int data(); native UniqueData data(int data);
}

static native void createUniqueData(@UniquePtr UniqueData u);
static native void storeUniqueData(@Const @UniquePtr UniqueData u);
static native @Const @UniquePtr UniqueData fetchUniqueData();

static native int constructorCount(); static native void constructorCount(int c);
static native int destructorCount(); static native void destructorCount(int c);

Expand Down Expand Up @@ -154,6 +169,23 @@ static class SharedData extends Pointer {
System.gc();
}

@Test public void testUniquePtr() {
System.out.println("UniquePtr");

UniqueData uniqueData = fetchUniqueData();
assertEquals(13, uniqueData.data());

uniqueData = new UniqueData(null);
createUniqueData(uniqueData);
assertEquals(42, uniqueData.data());

storeUniqueData(uniqueData);

uniqueData = fetchUniqueData();
assertEquals(42, uniqueData.data());
System.gc();
}

@Test public void testStdVector() {
System.out.println("StdVector");
int[] arr = {5, 7, 13, 37, 42};
Expand Down
18 changes: 18 additions & 0 deletions src/test/resources/org/bytedeco/javacpp/AdapterTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,24 @@ std::shared_ptr<SharedData> fetchSharedData() {
return s;
}

struct UniqueData {
int data;
UniqueData(int data) : data(data) { }
};

void createUniqueData(std::unique_ptr<UniqueData> *u) {
u->reset(new UniqueData(42));
}

std::unique_ptr<UniqueData> uniqueData(new UniqueData(13));
void storeUniqueData(const std::unique_ptr<UniqueData>* u) {
uniqueData->data = (*u)->data;
}

const std::unique_ptr<UniqueData>* fetchUniqueData() {
return &uniqueData;
}

std::vector<int> testStdVectorByVal(std::vector<int> v) {
return v;
}
Expand Down

0 comments on commit 8dcac09

Please sign in to comment.