From 67f0cfd1b5c467e930f9e8038cdda244a0e6669e Mon Sep 17 00:00:00 2001 From: Alexey Rochev Date: Sat, 9 Jan 2021 19:14:06 +0300 Subject: [PATCH 1/2] Generator: add BasicStringAdapter Add BasicStringAdapter, which is new version of StringAdapter that can work with any basic_string. Also add `@StdU16String` and `@StdU32String` annotations to use with `std::u16string` and `std::u32string`. --- .../javacpp/annotation/StdBasicString.java | 19 +++++++ .../javacpp/annotation/StdU16String.java | 15 ++++++ .../javacpp/annotation/StdU32String.java | 15 ++++++ .../org/bytedeco/javacpp/tools/Generator.java | 51 +++++++++++++++++++ .../org/bytedeco/javacpp/AdapterTest.java | 38 ++++++++++++-- .../org/bytedeco/javacpp/AdapterTest.h | 20 ++++++++ 6 files changed, 154 insertions(+), 4 deletions(-) create mode 100644 src/main/java/org/bytedeco/javacpp/annotation/StdBasicString.java create mode 100644 src/main/java/org/bytedeco/javacpp/annotation/StdU16String.java create mode 100644 src/main/java/org/bytedeco/javacpp/annotation/StdU32String.java diff --git a/src/main/java/org/bytedeco/javacpp/annotation/StdBasicString.java b/src/main/java/org/bytedeco/javacpp/annotation/StdBasicString.java new file mode 100644 index 000000000..9f62f39c6 --- /dev/null +++ b/src/main/java/org/bytedeco/javacpp/annotation/StdBasicString.java @@ -0,0 +1,19 @@ +package org.bytedeco.javacpp.annotation; + +import org.bytedeco.javacpp.Pointer; + +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; + +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD, ElementType.PARAMETER}) +@Adapter("BasicStringAdapter") +public @interface StdBasicString { + /** The template type of {@code BasicStringAdapter}. If not specified, it is + * inferred from the value type of the {@link Pointer} or Java array. */ + String value() default ""; +} \ No newline at end of file diff --git a/src/main/java/org/bytedeco/javacpp/annotation/StdU16String.java b/src/main/java/org/bytedeco/javacpp/annotation/StdU16String.java new file mode 100644 index 000000000..67464474f --- /dev/null +++ b/src/main/java/org/bytedeco/javacpp/annotation/StdU16String.java @@ -0,0 +1,15 @@ +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; + +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD, ElementType.PARAMETER}) +@Adapter("BasicStringAdapter") +public @interface StdU16String { + String value() default "unsigned short, char16_t"; +} \ No newline at end of file diff --git a/src/main/java/org/bytedeco/javacpp/annotation/StdU32String.java b/src/main/java/org/bytedeco/javacpp/annotation/StdU32String.java new file mode 100644 index 000000000..dca81c2b4 --- /dev/null +++ b/src/main/java/org/bytedeco/javacpp/annotation/StdU32String.java @@ -0,0 +1,15 @@ +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; + +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD, ElementType.PARAMETER}) +@Adapter("BasicStringAdapter") +public @interface StdU32String { + String value() default "int, char32_t"; +} \ No newline at end of file diff --git a/src/main/java/org/bytedeco/javacpp/tools/Generator.java b/src/main/java/org/bytedeco/javacpp/tools/Generator.java index 572dcf3be..182cca3d4 100644 --- a/src/main/java/org/bytedeco/javacpp/tools/Generator.java +++ b/src/main/java/org/bytedeco/javacpp/tools/Generator.java @@ -1163,6 +1163,57 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver out.println(" std::basic_string& str;"); out.println("};"); out.println(); + out.println("template class JavaCPP_hidden BasicStringAdapter {"); + out.println("public:"); + out.println(" BasicStringAdapter(const P* ptr, typename std::basic_string::size_type size, void* owner) : str(str2) { assign(const_cast(ptr), size, owner); }"); + out.println(); + out.println(" BasicStringAdapter(const std::basic_string& str) : size(0), owner(NULL), ptr(NULL), str2(str), str(str2) { }"); + out.println(" BasicStringAdapter( std::basic_string& str) : size(0), owner(NULL), ptr(NULL), str(str) { }"); + out.println(" BasicStringAdapter(const std::basic_string* str) : size(0), owner(NULL), ptr(NULL), str(*const_cast*>(str)) { }"); + out.println(); + out.println(" static void deallocate(void* owner) { delete[] static_cast(owner); }"); + out.println(); + out.println(" operator P*() {"); + out.println(" const T* data = str.data();"); + out.println(" if (str.size() > size) {"); + out.println(" ptr = new (std::nothrow) T[str.size() + 1]();"); + out.println(" }"); + out.println(" if (ptr && memcmp(ptr, data, sizeof(T) * str.size()) != 0) {"); + out.println(" memcpy(ptr, data, sizeof(T) * str.size());"); + out.println(" if (size > str.size()) ptr[str.size()] = 0;"); + out.println(" }"); + out.println(" size = str.size();"); + out.println(" owner = ptr;"); + out.println(" return reinterpret_cast(ptr);"); + out.println(" }"); + out.println(" operator const P*() {"); + out.println(" size = str.size();"); + out.println(" return reinterpret_cast(str.c_str());"); + out.println(" }"); + out.println(); + out.println(" operator std::basic_string&() { return str; }"); + out.println(" operator std::basic_string*() { return ptr ? &str : NULL; }"); + out.println(); + out.println(" void assign(P* ptr, typename std::basic_string::size_type size, void* owner) {"); + out.println(" this->ptr = reinterpret_cast(ptr);"); + out.println(" this->size = size;"); + out.println(" this->owner = owner;"); + out.println(" if (this->ptr) {"); + out.println(" str.assign(this->ptr, size > 0 ? size : std::char_traits::length(this->ptr));"); + out.println(" } else {"); + out.println(" str.clear();"); + out.println(" }"); + out.println(" }"); + out.println(); + out.println(" typename std::basic_string::size_type size;"); + out.println(" void* owner;"); + out.println(); + out.println("private:"); + out.println(" T* ptr;"); + out.println(" std::basic_string str2;"); + out.println(" std::basic_string& str;"); + out.println("};"); + out.println(); out.println("#ifdef SHARED_PTR_NAMESPACE"); out.println("template class SharedPtrAdapter {"); out.println("public:"); diff --git a/src/test/java/org/bytedeco/javacpp/AdapterTest.java b/src/test/java/org/bytedeco/javacpp/AdapterTest.java index be8a88186..3c0fb0df8 100644 --- a/src/test/java/org/bytedeco/javacpp/AdapterTest.java +++ b/src/test/java/org/bytedeco/javacpp/AdapterTest.java @@ -29,8 +29,11 @@ import org.bytedeco.javacpp.annotation.Function; import org.bytedeco.javacpp.annotation.Platform; import org.bytedeco.javacpp.annotation.SharedPtr; +import org.bytedeco.javacpp.annotation.StdBasicString; import org.bytedeco.javacpp.annotation.StdMove; import org.bytedeco.javacpp.annotation.StdString; +import org.bytedeco.javacpp.annotation.StdU16String; +import org.bytedeco.javacpp.annotation.StdU32String; import org.bytedeco.javacpp.annotation.StdVector; import org.bytedeco.javacpp.annotation.StdWString; import org.bytedeco.javacpp.annotation.UniquePtr; @@ -53,6 +56,14 @@ public class AdapterTest { static native @StdWString CharPointer testStdWString(@StdWString CharPointer str); static native @StdWString IntPointer testStdWString(@StdWString IntPointer str); + static native @StdBasicString("char") String testStdString2(@StdBasicString("char") String str); + static native @Cast("char*") @StdBasicString("char") BytePointer testStdString2(@Cast("char*") @StdBasicString("char") @StdString BytePointer str); + static native @Cast("wchar_t*") @StdBasicString("wchar_t") CharPointer testStdWString2(@Cast("wchar_t*") @StdBasicString("wchar_t") CharPointer str); + static native @Cast("wchar_t*") @StdBasicString("wchar_t") IntPointer testStdWString2(@Cast("wchar_t*") @StdBasicString("wchar_t") IntPointer str); + + static native @StdU16String CharPointer testStdU16String(@StdU16String CharPointer str); + static native @StdU32String IntPointer testStdU32String(@StdU32String IntPointer str); + static native String testCharString(String str); static native @Cast("char*") BytePointer testCharString(@Cast("char*") BytePointer str); @@ -61,6 +72,7 @@ public class AdapterTest { static native IntPointer testIntString(IntPointer str); static native @Const @ByRef @StdString byte[] getConstStdString(); + static native @Const @ByRef @Cast("char*") @StdBasicString("char") byte[] getConstStdString2(); static class SharedData extends Pointer { SharedData(Pointer p) { super(p); } @@ -133,28 +145,46 @@ static class MovedData extends Pointer { String textStr1 = "This is a normal ASCII string."; String textStr2 = testStdString(textStr1); assertEquals(textStr1, textStr2); + String textStr3 = testStdString2(textStr1); + assertEquals(textStr1, textStr3); BytePointer textPtr1 = new BytePointer(textStr1); BytePointer textPtr2 = testStdString(textPtr1); assertEquals(textStr1, textPtr1.getString()); assertEquals(textStr1, textPtr2.getString()); + BytePointer textPtr3 = testStdString2(textPtr1); + assertEquals(textStr1, textPtr3.getString()); + + CharPointer textCharPtr1 = new CharPointer(textStr1); + assertEquals(textStr1, textCharPtr1.getString()); + + IntPointer textIntPtr1 = new IntPointer(textStr1); + assertEquals(textStr1, textIntPtr1.getString()); if (Loader.getPlatform().startsWith("windows")) { // UTF-16 - CharPointer textCharPtr1 = new CharPointer(textStr1); CharPointer textCharPtr2 = testStdWString(textCharPtr1); - assertEquals(textStr1, textCharPtr1.getString()); assertEquals(textStr1, textCharPtr2.getString()); + CharPointer textCharPtr3 = testStdWString2(textCharPtr1); + assertEquals(textStr1, textCharPtr3.getString()); } else { // UTF-32 - IntPointer textIntPtr1 = new IntPointer(textStr1); IntPointer textIntPtr2 = testStdWString(textIntPtr1); - assertEquals(textStr1, textIntPtr1.getString()); assertEquals(textStr1, textIntPtr2.getString()); + IntPointer textIntPtr3 = testStdWString2(textIntPtr1); + assertEquals(textStr1, textIntPtr3.getString()); } + CharPointer textCharPtr4 = testStdU16String(textCharPtr1); + assertEquals(textStr1, textCharPtr4.getString()); + + IntPointer textIntPtr4 = testStdU32String(textIntPtr1); + assertEquals(textStr1, textIntPtr4.getString()); + byte[] test = getConstStdString(); assertEquals("test", new String(test)); + byte[] test2 = getConstStdString2(); + assertEquals("test", new String(test2)); System.gc(); } diff --git a/src/test/resources/org/bytedeco/javacpp/AdapterTest.h b/src/test/resources/org/bytedeco/javacpp/AdapterTest.h index ea677fc35..1aaa3d5ba 100644 --- a/src/test/resources/org/bytedeco/javacpp/AdapterTest.h +++ b/src/test/resources/org/bytedeco/javacpp/AdapterTest.h @@ -10,6 +10,22 @@ std::wstring testStdWString(std::wstring str) { return str; } +std::string testStdString2(std::string str) { + return str; +} + +std::wstring testStdWString2(std::wstring str) { + return str; +} + +std::u16string testStdU16String(std::u16string str) { + return str; +} + +std::u32string testStdU32String(std::u32string str) { + return str; +} + char *testCharString(const char *str) { return strdup(str); // memory leak... @@ -28,6 +44,10 @@ const std::string& getConstStdString() { return test; } +const std::string& getConstStdString2() { + return getConstStdString(); +} + int constructorCount = 0; int destructorCount = 0; From f1015310fd03c58af2d3ea0ffef9850e40df6259 Mon Sep 17 00:00:00 2001 From: Samuel Audet Date: Mon, 1 Feb 2021 09:24:07 +0900 Subject: [PATCH 2/2] Update CHANGELOG.md --- CHANGELOG.md | 1 + src/test/java/org/bytedeco/javacpp/AdapterTest.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26f1b7982..a52bbf3a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ + * Add `BasicStringAdapter` and corresponding `@StdBasicString`, `@StdU16String`, and `@StdU32String` annotations ([pull #448](https://github.com/bytedeco/javacpp/pull/448)) * Fix `Parser` failures on `try` blocks as function body, nested class templates, and aliases to namespaces starting with `::` * Prevent `Loader` from failing to find, load, or link libraries multiple times * Fix `Pointer.getPointer()` methods sometimes calling the wrong constructor ([issue bytedeco/javacv#1556](https://github.com/bytedeco/javacv/issues/1556)) diff --git a/src/test/java/org/bytedeco/javacpp/AdapterTest.java b/src/test/java/org/bytedeco/javacpp/AdapterTest.java index 3c0fb0df8..f6b88197a 100644 --- a/src/test/java/org/bytedeco/javacpp/AdapterTest.java +++ b/src/test/java/org/bytedeco/javacpp/AdapterTest.java @@ -57,7 +57,7 @@ public class AdapterTest { static native @StdWString IntPointer testStdWString(@StdWString IntPointer str); static native @StdBasicString("char") String testStdString2(@StdBasicString("char") String str); - static native @Cast("char*") @StdBasicString("char") BytePointer testStdString2(@Cast("char*") @StdBasicString("char") @StdString BytePointer str); + static native @Cast("char*") @StdBasicString("char") BytePointer testStdString2(@Cast("char*") @StdBasicString("char") BytePointer str); static native @Cast("wchar_t*") @StdBasicString("wchar_t") CharPointer testStdWString2(@Cast("wchar_t*") @StdBasicString("wchar_t") CharPointer str); static native @Cast("wchar_t*") @StdBasicString("wchar_t") IntPointer testStdWString2(@Cast("wchar_t*") @StdBasicString("wchar_t") IntPointer str);