Skip to content

Commit

Permalink
Adding generic storage on Android
Browse files Browse the repository at this point in the history
  • Loading branch information
gershnik committed Dec 8, 2021
1 parent 0f13aab commit 2086bea
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 40 deletions.
7 changes: 5 additions & 2 deletions doc/Android.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
## Android platform conversions

Currently there is only one storage type available on Android.
On Android there are two storage types available. The default one is optimized for interoperability with Java. It stores a sequence of `char16_t` which can be converted to `jstring` with the least amount of JNI overhead.

`sys_string` internally stores a sequence of `char16_t` which can be converted to `jstring` with the least amount of JNI overhead. A conversion is not-trivial, however. It incurs allocation and copying. (A possible approach to store global references to `jstring` in `sys_string` is not feasible for many reasons, among them the fact that global reference table is of limited size).
Additionally you can chose a "generic Unix" storage which stores `char *` and is meant to interoperate with plain Unix API. It can be selected via `#define SYS_STRING_USE_GENERIC 1` and is described under [Linux](Linux.md).

With Java-optimized storage a conversion to and from `jstring` is not-trivial. It incurs allocation on Java or native heap and copying between them.
(A possible approach to store global references to `jstring` in `sys_string` is not feasible for many reasons, among them the fact that global reference table can be of limited size).
As expected with JNI, all conversion require JNIEnv * argument.

```cpp
Expand Down
1 change: 0 additions & 1 deletion doc/Usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
- [Joining](#joining)
- [Prefix, suffix and infix handling](#prefix-suffix-and-infix-handling)
- [Replacing content](#replacing-content)
- [Odds and ends](#odds-and-ends)

<!-- /TOC -->

Expand Down
29 changes: 23 additions & 6 deletions lib/inc/sys_string/impl/platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,32 @@
#endif

#elif defined(__ANDROID__)

#include <sys_string/impl/platforms/android_java.h>
#include <sys_string/impl/platforms/unix_generic.h>

namespace sysstr
{
using sys_string = sys_string_android;
using sys_string_builder = sys_string_android_builder;
}
#if defined(SYS_STRING_USE_GENERIC)

namespace sysstr
{
using sys_string = sys_string_generic;
using sys_string_builder = sys_string_generic_builder;
}

#define SYS_STRING_STATIC SYS_STRING_STATIC_ANDROID
#define SYS_STRING_STATIC SYS_STRING_STATIC_GENERIC

#else


namespace sysstr
{
using sys_string = sys_string_android;
using sys_string_builder = sys_string_android_builder;
}

#define SYS_STRING_STATIC SYS_STRING_STATIC_ANDROID

#endif

#elif defined(_WIN32)
#include <sys_string/impl/platforms/windows_bstr.h>
Expand Down
8 changes: 8 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
unix_gen
)

elseif (${CMAKE_SYSTEM_NAME} STREQUAL Android)

set (STORAGE_TYPES
andr
unix_gen
)

else()

set (STORAGE_TYPES
Expand All @@ -53,6 +60,7 @@ set(STORAGE_FLAG_bstr SYS_STRING_WIN_BSTR=1)
set(STORAGE_FLAG_hstring SYS_STRING_WIN_HSTRING=1)
set(STORAGE_FLAG_win_gen "")
set(STORAGE_FLAG_cfstr "")
set(STORAGE_FLAG_andr "")
set(STORAGE_FLAG_unix_gen SYS_STRING_USE_GENERIC=1)

set(TEST_COMMAND "")
Expand Down
85 changes: 54 additions & 31 deletions test/test_android.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,44 +15,67 @@ using namespace sysstr;
extern JavaVM * g_vm;
extern JNIEnv * g_env;

TEST_CASE( "Android Conversions", "[android]") {
#if !SYS_STRING_USE_GENERIC

CHECK(sys_string().make_jstring(g_env) == nullptr);
CHECK(sys_string(g_env, nullptr) == S(""));
TEST_CASE( "Android Conversions", "[android]") {

jstring jstr = S("a水𐀀𝄞bcå🤢").make_jstring(g_env);
REQUIRE(jstr);
CHECK(g_env->GetStringLength(jstr) == S("a水𐀀𝄞bcå🤢").storage_size());
CHECK(sys_string().make_jstring(g_env) == nullptr);
CHECK(sys_string(g_env, nullptr) == S(""));

jstr = g_env->NewString((const jchar *)u"a水𐀀𝄞bcå🤢", std::size(u"a水𐀀𝄞bcå🤢") - 1);
sys_string str(g_env, jstr);
CHECK(str == S("a水𐀀𝄞bcå🤢"));
}
jstring jstr = S("a水𐀀𝄞bcå🤢").make_jstring(g_env);
REQUIRE(jstr);
CHECK(g_env->GetStringLength(jstr) == S("a水𐀀𝄞bcå🤢").storage_size());

jstr = g_env->NewString((const jchar *)u"a水𐀀𝄞bcå🤢", std::size(u"a水𐀀𝄞bcå🤢") - 1);
sys_string str(g_env, jstr);
CHECK(str == S("a水𐀀𝄞bcå🤢"));
}

TEST_CASE( "Android error handling", "[android]") {
jclass integer_cls = g_env->FindClass("java/lang/Integer");
REQUIRE(integer_cls);
jmethodID integer_ctor = g_env->GetMethodID(integer_cls, "<init>", "()V");
REQUIRE(integer_ctor);

jobject an_integer = g_env->NewObject(integer_cls, integer_ctor);
REQUIRE(an_integer);

sys_string str(g_env, (jstring)an_integer);
CHECK(str == sys_string());

sys_string str1(g_env, (jstring)integer_cls);
CHECK(str1 == sys_string());

TEST_CASE( "Android error handling", "[android]") {
jclass integer_cls = g_env->FindClass("java/lang/Integer");
REQUIRE(integer_cls);
jmethodID integer_ctor = g_env->GetMethodID(integer_cls, "<init>", "()V");
REQUIRE(integer_ctor);

jobject an_integer = g_env->NewObject(integer_cls, integer_ctor);
REQUIRE(an_integer);
jclass exception_cls = g_env->FindClass("java/lang/Exception");
REQUIRE(exception_cls);

jstring jstr = g_env->NewString((const jchar *)u"a水𐀀𝄞bcå🤢", std::size(u"a水𐀀𝄞bcå🤢") - 1);
REQUIRE(jstr);
REQUIRE(g_env->ThrowNew(exception_cls, "haha") == 0);

sys_string str(g_env, (jstring)an_integer);
CHECK(str == sys_string());
CHECK(sys_string(g_env, jstr) == S("a水𐀀𝄞bcå🤢"));
CHECK(S("haha").make_jstring(g_env));

sys_string str1(g_env, (jstring)integer_cls);
CHECK(str1 == sys_string());
g_env->ExceptionClear();
}

jclass exception_cls = g_env->FindClass("java/lang/Exception");
REQUIRE(exception_cls);

jstring jstr = g_env->NewString((const jchar *)u"a水𐀀𝄞bcå🤢", std::size(u"a水𐀀𝄞bcå🤢") - 1);
REQUIRE(jstr);
REQUIRE(g_env->ThrowNew(exception_cls, "haha") == 0);
#else

CHECK(sys_string(g_env, jstr) == S("a水𐀀𝄞bcå🤢"));
CHECK(S("haha").make_jstring(g_env));
TEST_CASE( "Android Conversions", "[android]") {

g_env->ExceptionClear();
REQUIRE(sys_string().c_str());
CHECK(strcmp(sys_string().c_str(), "") == 0);

REQUIRE(S("").c_str());
CHECK(strcmp(S("").c_str(), "") == 0);

REQUIRE(sys_string("").c_str());
CHECK(strcmp(sys_string("").c_str(), "") == 0);

REQUIRE(sys_string((const char*)nullptr).c_str());
CHECK(strcmp(sys_string((const char*)nullptr).c_str(), "") == 0);

CHECK(strcmp(sys_string("a水𐀀𝄞bcå🤢").c_str(), "a水𐀀𝄞bcå🤢") == 0);
}

#endif

0 comments on commit 2086bea

Please sign in to comment.