From 1187ce22391b5db8b674e7bc8bd9113205766b4e Mon Sep 17 00:00:00 2001 From: Yauheni Khnykin Date: Tue, 14 May 2024 10:15:44 +0200 Subject: [PATCH] Moves Date/Duration utils to cpp Signed-off-by: Yauheni Khnykin --- .../JniCppConversionUtilsHeader.mustache | 122 ++++++++---------- ...iCppConversionUtilsImplementation.mustache | 104 +++++++++++---- 2 files changed, 136 insertions(+), 90 deletions(-) diff --git a/gluecodium/src/main/resources/templates/jni/utils/JniCppConversionUtilsHeader.mustache b/gluecodium/src/main/resources/templates/jni/utils/JniCppConversionUtilsHeader.mustache index dd0937ebc8..48a0869bae 100644 --- a/gluecodium/src/main/resources/templates/jni/utils/JniCppConversionUtilsHeader.mustache +++ b/gluecodium/src/main/resources/templates/jni/utils/JniCppConversionUtilsHeader.mustache @@ -52,37 +52,38 @@ namespace jni /** * Converts a JNI jstring to an std::string. */ -JNIEXPORT std::string convert_from_jni( JNIEnv* env, const JniReference& jvalue, TypeId ); -JNIEXPORT std::string convert_from_jni( JNIEnv* env, const JniReference& jvalue, TypeId ); +JNIEXPORT std::string convert_from_jni( JNIEnv* const env, const JniReference& jvalue, TypeId ); +JNIEXPORT std::string convert_from_jni( JNIEnv* const env, const JniReference& jvalue, TypeId ); JNIEXPORT std::optional convert_from_jni( - JNIEnv* env, const JniReference& jvalue, TypeId> ); + JNIEnv* const env, const JniReference& jvalue, TypeId> ); JNIEXPORT std::optional convert_from_jni( - JNIEnv* env, const JniReference& jvalue, TypeId> ); + JNIEnv* const env, const JniReference& jvalue, TypeId> ); /** * Converts a jbyteArray to a byte buffer */ -JNIEXPORT std::shared_ptr< ::std::vector< uint8_t > > convert_from_jni( - JNIEnv* env, const JniReference& jvalue, TypeId>> ); +JNIEXPORT std::shared_ptr<::std::vector> convert_from_jni( + JNIEnv* const env, const JniReference& jvalue, TypeId>> ); JNIEXPORT std::optional>> convert_from_jni( - JNIEnv* env, const JniReference& jvalue, + JNIEnv* const env, const JniReference& jvalue, TypeId>>> ); /** * Converts a Java Date object to an std::chrono::time_point. */ + +jlong get_time_ms_epoch(JNIEnv* const env, const JniReference& jvalue) noexcept; + template std::chrono::time_point -convert_from_jni(JNIEnv* env, const JniReference& jvalue, TypeId>) { +convert_from_jni(JNIEnv* const env, const JniReference& jvalue, TypeId>) { if (!jvalue) { {{>common/InternalNamespace}}jni::throw_new_null_pointer_exception(env); return {}; } - auto javaDateClass = find_class(env, "java/util/Date"); - auto getTimeMethodId = env->GetMethodID(javaDateClass.get(), "getTime", "()J"); - jlong time_ms_epoch = call_java_method(env, jvalue, getTimeMethodId); + const jlong time_ms_epoch = get_time_ms_epoch(env, jvalue); using namespace std::chrono; return time_point(duration_cast(milliseconds(time_ms_epoch))); @@ -91,59 +92,45 @@ convert_from_jni(JNIEnv* env, const JniReference& jvalue, TypeId std::optional> convert_from_jni( - JNIEnv* env, + JNIEnv* const env, const JniReference& jvalue, TypeId>> ) { return jvalue ? std::optional>( - convert_from_jni(env, jvalue, TypeId>{}) - ) + convert_from_jni(env, jvalue, TypeId>{})) : std::optional>{}; } /** * Converts a Java Duration object to an std::chrono::duration<>. */ + +std::intmax_t get_duration_from_java_duration(JNIEnv* const env, + const JniReference& jvalue, + std::intmax_t dest_den, + std::intmax_t dest_num); + template std::chrono::duration -convert_from_jni(JNIEnv* env, const JniReference& jvalue, TypeId>) { +convert_from_jni(JNIEnv* const env, const JniReference& jvalue, TypeId>) +{ if (!jvalue) { {{>common/InternalNamespace}}jni::throw_new_null_pointer_exception(env); return {}; } - auto& javaDurationClass = get_cached_duration_class(); - auto getSecondsMethodId = env->GetMethodID(javaDurationClass.get(), "getSeconds", "()J"); - jlong seconds_value = call_java_method(env, jvalue, getSecondsMethodId); - auto getNanoMethodId = env->GetMethodID(javaDurationClass.get(), "getNano", "()I"); - jint nano_value = call_java_method(env, jvalue, getNanoMethodId); - - using namespace std::chrono; + const auto result_value = get_duration_from_java_duration(env, jvalue, Period::den, Period::num); - auto seconds_division = std::lldiv(seconds_value * Period::den, Period::num); - auto combined_nano_value = - duration_cast(seconds(seconds_division.rem)).count() + nano_value; - auto num = Period::den * nanoseconds::period::num; - auto den = Period::num * nanoseconds::period::den; - auto nano_division = std::lldiv(combined_nano_value * num, den); - auto result_value = seconds_division.quot + nano_division.quot; - - // Rounding - if (2 * nano_division.rem >= den) { - result_value += 1; - } - - return duration(result_value); + return std::chrono::duration(result_value); } template std::optional> convert_from_jni( - JNIEnv* env, const JniReference& jvalue, - TypeId>> -) { - + JNIEnv* const env, const JniReference& jvalue, + TypeId>>) +{ return jvalue ? std::optional>( convert_from_jni( env, jvalue, TypeId>{})) @@ -154,9 +141,10 @@ convert_from_jni( * Converts a Java Locale object to {{>common/InternalNamespace}}Locale. */ JNIEXPORT {{>common/InternalNamespace}}Locale convert_from_jni( - JNIEnv* env, const JniReference& jvalue, TypeId<{{>common/InternalNamespace}}Locale>); + JNIEnv* const env, const JniReference& jvalue, + TypeId<{{>common/InternalNamespace}}Locale>); JNIEXPORT std::optional<{{>common/InternalNamespace}}Locale> convert_from_jni( - JNIEnv* env, const JniReference& jvalue, + JNIEnv* const env, const JniReference& jvalue, TypeIdcommon/InternalNamespace}}Locale>>); // -------------------- C++ to JNI conversion functions -------------------------------------------- @@ -164,62 +152,66 @@ JNIEXPORT std::optional<{{>common/InternalNamespace}}Locale> convert_from_jni( /** * Converts an std::string to a JNI jstring */ -JNIEXPORT JniReference convert_to_jni( JNIEnv* env, const std::string& nvalue ); -JNIEXPORT JniReference convert_to_jni( JNIEnv* env, const std::optional& nvalue ); +JNIEXPORT JniReference convert_to_jni( JNIEnv* const env, const std::string& nvalue ) noexcept; +JNIEXPORT JniReference convert_to_jni( JNIEnv* const env, const std::optional& nvalue ) noexcept; /** * Converts a byte buffer to a jbyteArray */ -JNIEXPORT JniReference convert_to_jni( JNIEnv* env, const std::shared_ptr< ::std::vector< uint8_t > >& nvalue ); JNIEXPORT JniReference convert_to_jni( - JNIEnv* env, const std::optional< std::shared_ptr< ::std::vector< uint8_t > > >& nvalue ); + JNIEnv* const env, const std::shared_ptr< ::std::vector< uint8_t > >& nvalue ) noexcept; +JNIEXPORT JniReference convert_to_jni( + JNIEnv* const env, const std::optional< std::shared_ptr< ::std::vector< uint8_t > > >& nvalue ) noexcept; /** * Converts an std::chrono::time_point to a Java Date object. */ + +JniReference create_date_new_object(JNIEnv* const env, const std::chrono::milliseconds& time_epoch); + template JniReference -convert_to_jni(JNIEnv* env, const std::chrono::time_point& nvalue) { - auto javaDateClass = find_class(env, "java/util/Date"); - jlong time_ms_epoch = std::chrono::duration_cast(nvalue.time_since_epoch()).count(); - - auto constructorMethodId = env->GetMethodID(javaDateClass.get(), "", "(J)V"); - return new_object(env, javaDateClass, constructorMethodId, time_ms_epoch); +convert_to_jni(JNIEnv* const env, const std::chrono::time_point& nvalue) +{ + return create_date_new_object(env, std::chrono::duration_cast(nvalue.time_since_epoch())); } template JniReference -convert_to_jni(JNIEnv* env, const std::optional>& nvalue) { +convert_to_jni(JNIEnv* const env, const std::optional>& nvalue) +{ return nvalue ? convert_to_jni(env, *nvalue) : JniReference{}; } /** * Converts an std::chrono::duration<> to a Java Duration object. */ -template + JniReference -convert_to_jni(JNIEnv* env, const std::chrono::duration& nvalue) { - auto& javaDurationClass = get_cached_duration_class(); - auto factoryMethodId = env->GetStaticMethodID(javaDurationClass.get(), "ofSeconds", "(JJ)L{{durationPackage}}/Duration;"); +create_duration_new_object(JNIEnv* const env, std::intmax_t seconds, std::intmax_t nanos) noexcept; +template +JniReference +convert_to_jni(JNIEnv* const env, const std::chrono::duration& nvalue) { using namespace std::chrono; - auto seconds_duration = duration_cast(nvalue); - auto seconds_value = duration_cast(nvalue).count(); - auto nanos_adjustment = duration_cast(nvalue - seconds_duration).count(); - return make_local_ref(env, env->CallStaticObjectMethod(javaDurationClass.get(), factoryMethodId, seconds_value, nanos_adjustment)); + const auto seconds_duration = duration_cast(nvalue); + const auto seconds_value = duration_cast(nvalue).count(); + const auto nanos_adjustment = duration_cast(nvalue - seconds_duration).count(); + return create_duration_new_object(env, seconds_value, nanos_adjustment); } /** * Converts {{>common/InternalNamespace}}Locale to a Java Locale object. */ -JNIEXPORT JniReference convert_to_jni(JNIEnv* env, const {{>common/InternalNamespace}}Locale& nvalue); JNIEXPORT JniReference convert_to_jni( - JNIEnv* env, const std::optional<{{>common/InternalNamespace}}Locale>& nvalue); + JNIEnv* const env, const {{>common/InternalNamespace}}Locale& nvalue) noexcept; +JNIEXPORT JniReference convert_to_jni( + JNIEnv* const env, const std::optional<{{>common/InternalNamespace}}Locale>& nvalue) noexcept; template JNIEXPORT JniReference convert_to_jni( - JNIEnv* env, const std::optional>& nvalue ) { - + JNIEnv* const env, const std::optional>& nvalue ) +{ return nvalue ? convert_to_jni(env, *nvalue) : JniReference{}; } diff --git a/gluecodium/src/main/resources/templates/jni/utils/JniCppConversionUtilsImplementation.mustache b/gluecodium/src/main/resources/templates/jni/utils/JniCppConversionUtilsImplementation.mustache index 4e003e9b75..b7c83ad55c 100644 --- a/gluecodium/src/main/resources/templates/jni/utils/JniCppConversionUtilsImplementation.mustache +++ b/gluecodium/src/main/resources/templates/jni/utils/JniCppConversionUtilsImplementation.mustache @@ -33,7 +33,7 @@ namespace jni // ------------------- JNI to C++ conversion functions --------------------------------------------- std::string -convert_string_from_jni( JNIEnv* env, jstring java_string ) +convert_string_from_jni( JNIEnv* const env, jstring java_string ) { const char* jbuffer = env->GetStringUTFChars( java_string, nullptr ); auto nresult = std::string( jbuffer ); @@ -42,7 +42,7 @@ convert_string_from_jni( JNIEnv* env, jstring java_string ) } std::string -convert_from_jni( JNIEnv* env, const JniReference& jvalue, TypeId ) +convert_from_jni( JNIEnv* const env, const JniReference& jvalue, TypeId ) { if ( !jvalue ) { @@ -54,7 +54,7 @@ convert_from_jni( JNIEnv* env, const JniReference& jvalue, TypeId& jvalue, TypeId ) +convert_from_jni( JNIEnv* const env, const JniReference& jvalue, TypeId ) { if ( !jvalue ) { @@ -66,7 +66,7 @@ convert_from_jni( JNIEnv* env, const JniReference& jvalue, TypeId -convert_from_jni( JNIEnv* env, const JniReference& jvalue, TypeId> ) +convert_from_jni( JNIEnv* const env, const JniReference& jvalue, TypeId> ) { return jvalue ? std::optional( convert_string_from_jni( env, static_cast( jvalue.get( ) ) ) ) @@ -74,7 +74,7 @@ convert_from_jni( JNIEnv* env, const JniReference& jvalue, TypeId -convert_from_jni( JNIEnv* env, const JniReference& jvalue, TypeId> ) +convert_from_jni( JNIEnv* const env, const JniReference& jvalue, TypeId> ) { return jvalue ? std::optional( convert_string_from_jni( env, jvalue.get( ) ) ) @@ -82,7 +82,7 @@ convert_from_jni( JNIEnv* env, const JniReference& jvalue, TypeId > -convert_from_jni( JNIEnv* env, const JniReference& jvalue, +convert_from_jni( JNIEnv* const env, const JniReference& jvalue, TypeId>> ) { if ( !jvalue ) @@ -91,15 +91,15 @@ convert_from_jni( JNIEnv* env, const JniReference& jvalue, return {}; } - size_t size = static_cast< size_t >( env->GetArrayLength( jvalue.get() ) ); - auto nresult = std::make_shared< std::vector< uint8_t > >( size ); - jbyte* jbuffer = reinterpret_cast< jbyte* >( nresult->data( ) ); - env->GetByteArrayRegion( jvalue.get(), 0, size, jbuffer ); + size_t size = static_cast< size_t >(env->GetArrayLength(jvalue.get())); + auto nresult = std::make_shared>(size); + jbyte* jbuffer = reinterpret_cast(nresult->data()); + env->GetByteArrayRegion(jvalue.get(), 0, size, jbuffer); return nresult; } std::optional< std::shared_ptr< std::vector< uint8_t > > > -convert_from_jni( JNIEnv* env, +convert_from_jni( JNIEnv* const env, const JniReference& jvalue, TypeId>>> ) { @@ -109,8 +109,16 @@ convert_from_jni( JNIEnv* env, : std::optional< std::shared_ptr< std::vector< uint8_t > > >{}; } +jlong get_time_ms_epoch(JNIEnv* const env, const JniReference& jvalue) noexcept +{ + const auto java_date_class = find_class(env, "java/util/Date"); + const auto get_time_method_id = env->GetMethodID(java_date_class.get(), "getTime", "()J"); + return call_java_method(env, jvalue, get_time_method_id); +} + {{>common/InternalNamespace}}Locale -convert_from_jni(JNIEnv* env, const JniReference& jvalue, TypeId<{{>common/InternalNamespace}}Locale>) { +convert_from_jni(JNIEnv* const env, const JniReference& jvalue, TypeId<{{>common/InternalNamespace}}Locale>) +{ if (!jvalue) { {{>common/InternalNamespace}}jni::throw_new_null_pointer_exception(env); return {{>common/InternalNamespace}}Locale(); @@ -130,8 +138,7 @@ convert_from_jni(JNIEnv* env, const JniReference& jvalue, TypeId<{{>com } std::optional<{{>common/InternalNamespace}}Locale> -convert_from_jni(JNIEnv* env, const JniReference& jvalue, - TypeIdcommon/InternalNamespace}}Locale>>) +convert_from_jni(JNIEnv* const env, const JniReference& jvalue, TypeIdcommon/InternalNamespace}}Locale>>) { return jvalue ? std::optional<{{>common/InternalNamespace}}Locale>( @@ -142,13 +149,13 @@ convert_from_jni(JNIEnv* env, const JniReference& jvalue, // -------------------- C++ to JNI conversion functions -------------------------------------------- JniReference -convert_to_jni( JNIEnv* env, const std::string& nvalue ) +convert_to_jni( JNIEnv* const env, const std::string& nvalue ) noexcept { return make_local_ref(env, env->NewStringUTF( nvalue.c_str( ) )); } JniReference -convert_to_jni( JNIEnv* env, const std::optional& nvalue ) +convert_to_jni( JNIEnv* const env, const std::optional& nvalue ) noexcept { return nvalue ? make_local_ref(env, env->NewStringUTF( nvalue->c_str( ) )) @@ -156,29 +163,76 @@ convert_to_jni( JNIEnv* env, const std::optional& nvalue ) } JniReference -convert_to_jni( JNIEnv* env, const std::shared_ptr< std::vector< uint8_t > >& nvalue ) +convert_to_jni(JNIEnv* const env, const std::shared_ptr >& nvalue) noexcept { - if ( !nvalue ) + if (!nvalue) { return make_local_ref(env, env->NewByteArray(0)); } - jsize size = static_cast< jsize >( nvalue->size( ) ); + const jsize size = static_cast< jsize >(nvalue->size()); auto jresult = make_local_ref(env, env->NewByteArray( size )); - const jbyte* jbuffer = reinterpret_cast< const jbyte* >( nvalue->data( ) ); - env->SetByteArrayRegion( jresult.get(), 0, size, jbuffer ); + const jbyte* const jbuffer = reinterpret_cast< const jbyte* >( nvalue->data( ) ); + env->SetByteArrayRegion(jresult.get(), 0, size, jbuffer); return jresult; } -JniReference< jbyteArray > -convert_to_jni( JNIEnv* env, const std::optional< std::shared_ptr< std::vector< uint8_t > > >& nvalue ) +JniReference +convert_to_jni(JNIEnv* const env, const std::optional< std::shared_ptr> >& nvalue) noexcept { return nvalue ? convert_to_jni( env, *nvalue ) : JniReference< jbyteArray >{}; } +JniReference create_date_new_object(JNIEnv* const env, const std::chrono::milliseconds& time_epoch) +{ + const auto java_date_class = find_class(env, "java/util/Date"); + const jlong time_ms_epoch = time_epoch.count(); + + const auto constructor_method_id = env->GetMethodID(java_date_class.get(), "", "(J)V"); + return new_object(env, java_date_class, constructor_method_id, time_ms_epoch); +} + +std::intmax_t get_duration_from_java_duration(JNIEnv* const env, + const JniReference& jvalue, + const std::intmax_t dest_den, + const std::intmax_t dest_num) +{ + const auto& java_duration_class = get_cached_duration_class(); + const auto get_seconds_method_id = env->GetMethodID(java_duration_class.get(), "getSeconds", "()J"); + const jlong seconds_value = call_java_method(env, jvalue, get_seconds_method_id); + const auto get_nano_method_id = env->GetMethodID(java_duration_class.get(), "getNano", "()I"); + const jint nano_value = call_java_method(env, jvalue, get_nano_method_id); + + using namespace std::chrono; + + const auto seconds_division = std::lldiv(seconds_value * dest_den, dest_num); + const auto combined_nano_value = + duration_cast(seconds(seconds_division.rem)).count() + nano_value; + const auto num = dest_den * nanoseconds::period::num; + const auto den = dest_num * nanoseconds::period::den; + const auto nano_division = std::lldiv(combined_nano_value * num, den); + auto result_value = seconds_division.quot + nano_division.quot; + + // Rounding + if (2 * nano_division.rem >= den) + { + result_value += 1; + } + + return result_value; +} + +JniReference +create_duration_new_object(JNIEnv* const env, std::intmax_t seconds, std::intmax_t nanos) noexcept +{ + const auto& java_duration_class = get_cached_duration_class(); + const auto factory_method_id = env->GetStaticMethodID(java_duration_class.get(), "ofSeconds", "(JJ)L{{durationPackage}}/Duration;"); + return make_local_ref(env, env->CallStaticObjectMethod(java_duration_class.get(), factory_method_id, seconds, nanos)); +} + JniReference -convert_to_jni(JNIEnv* env, const {{>common/InternalNamespace}}Locale& nvalue) { +convert_to_jni(JNIEnv* const env, const {{>common/InternalNamespace}}Locale& nvalue) noexcept { auto localeBuilderClass = find_class(env, "java/util/Locale$Builder"); auto builder = create_object(env, localeBuilderClass); if (nvalue.language_tag) { @@ -213,7 +267,7 @@ convert_to_jni(JNIEnv* env, const {{>common/InternalNamespace}}Locale& nvalue) { } JniReference -convert_to_jni(JNIEnv* env, const std::optional<{{>common/InternalNamespace}}Locale>& nvalue) { +convert_to_jni(JNIEnv* const env, const std::optional<{{>common/InternalNamespace}}Locale>& nvalue) noexcept { return nvalue ? convert_to_jni(env, *nvalue) : JniReference{}; }