Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generator: refactor StringAdapter to support std::u16string #448

Merged
merged 2 commits into from
Feb 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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))
Expand Down
19 changes: 19 additions & 0 deletions src/main/java/org/bytedeco/javacpp/annotation/StdBasicString.java
Original file line number Diff line number Diff line change
@@ -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 "";
}
15 changes: 15 additions & 0 deletions src/main/java/org/bytedeco/javacpp/annotation/StdU16String.java
Original file line number Diff line number Diff line change
@@ -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";
}
15 changes: 15 additions & 0 deletions src/main/java/org/bytedeco/javacpp/annotation/StdU32String.java
Original file line number Diff line number Diff line change
@@ -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";
}
51 changes: 51 additions & 0 deletions src/main/java/org/bytedeco/javacpp/tools/Generator.java
Original file line number Diff line number Diff line change
Expand Up @@ -1163,6 +1163,57 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver
out.println(" std::basic_string<T>& str;");
out.println("};");
out.println();
out.println("template<typename P, typename T = P> class JavaCPP_hidden BasicStringAdapter {");
out.println("public:");
out.println(" BasicStringAdapter(const P* ptr, typename std::basic_string<T>::size_type size, void* owner) : str(str2) { assign(const_cast<P*>(ptr), size, owner); }");
out.println();
out.println(" BasicStringAdapter(const std::basic_string<T>& str) : size(0), owner(NULL), ptr(NULL), str2(str), str(str2) { }");
out.println(" BasicStringAdapter( std::basic_string<T>& str) : size(0), owner(NULL), ptr(NULL), str(str) { }");
out.println(" BasicStringAdapter(const std::basic_string<T>* str) : size(0), owner(NULL), ptr(NULL), str(*const_cast<std::basic_string<T>*>(str)) { }");
out.println();
out.println(" static void deallocate(void* owner) { delete[] static_cast<T*>(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<P*>(ptr);");
out.println(" }");
out.println(" operator const P*() {");
out.println(" size = str.size();");
out.println(" return reinterpret_cast<const P*>(str.c_str());");
out.println(" }");
out.println();
out.println(" operator std::basic_string<T>&() { return str; }");
out.println(" operator std::basic_string<T>*() { return ptr ? &str : NULL; }");
out.println();
out.println(" void assign(P* ptr, typename std::basic_string<T>::size_type size, void* owner) {");
out.println(" this->ptr = reinterpret_cast<T*>(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<T>::length(this->ptr));");
out.println(" } else {");
out.println(" str.clear();");
out.println(" }");
out.println(" }");
out.println();
out.println(" typename std::basic_string<T>::size_type size;");
out.println(" void* owner;");
out.println();
out.println("private:");
out.println(" T* ptr;");
out.println(" std::basic_string<T> str2;");
out.println(" std::basic_string<T>& str;");
out.println("};");
out.println();
out.println("#ifdef SHARED_PTR_NAMESPACE");
out.println("template<class T> class SharedPtrAdapter {");
out.println("public:");
Expand Down
38 changes: 34 additions & 4 deletions src/test/java/org/bytedeco/javacpp/AdapterTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
saudet marked this conversation as resolved.
Show resolved Hide resolved
import org.bytedeco.javacpp.annotation.StdVector;
import org.bytedeco.javacpp.annotation.StdWString;
import org.bytedeco.javacpp.annotation.UniquePtr;
Expand All @@ -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") 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);

Expand All @@ -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); }
Expand Down Expand Up @@ -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());
saudet marked this conversation as resolved.
Show resolved Hide resolved
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();
}

Expand Down
20 changes: 20 additions & 0 deletions src/test/resources/org/bytedeco/javacpp/AdapterTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -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...
saudet marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -28,6 +44,10 @@ const std::string& getConstStdString() {
return test;
}

const std::string& getConstStdString2() {
return getConstStdString();
}

int constructorCount = 0;
int destructorCount = 0;

Expand Down