diff options
Diffstat (limited to 'native')
9 files changed, 120 insertions, 112 deletions
diff --git a/native/jni/HostUnitTests.mk b/native/jni/HostUnitTests.mk index 6967d9b87..e30d50a2e 100644 --- a/native/jni/HostUnitTests.mk +++ b/native/jni/HostUnitTests.mk @@ -12,6 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +# Host build is never supported in unbundled (NDK/tapas) build +ifeq (,$(TARGET_BUILD_APPS)) + # HACK: Temporarily disable host tool build on Mac until the build system is ready for C++11. LATINIME_HOST_OSNAME := $(shell uname -s) ifneq ($(LATINIME_HOST_OSNAME), Darwin) # TODO: Remove this @@ -26,8 +29,10 @@ include $(LOCAL_PATH)/NativeFileList.mk #################### Host library for unit test # TODO: Remove -std=c++11 once it is set by default on host build. LATIN_IME_SRC_DIR := src +LOCAL_ADDRESS_SANITIZER := true LOCAL_CFLAGS += -std=c++11 -Wno-unused-parameter -Wno-unused-function LOCAL_CLANG := true +LOCAL_CXX_STL := libc++ LOCAL_C_INCLUDES += $(LOCAL_PATH)/$(LATIN_IME_SRC_DIR) LOCAL_MODULE := liblatinime_host_static_for_unittests LOCAL_MODULE_TAGS := optional @@ -37,9 +42,11 @@ include $(BUILD_HOST_STATIC_LIBRARY) #################### Host native tests include $(CLEAR_VARS) LATIN_IME_TEST_SRC_DIR := tests +LOCAL_ADDRESS_SANITIZER := true # TODO: Remove -std=c++11 once it is set by default on host build. LOCAL_CFLAGS += -std=c++11 -Wno-unused-parameter -Wno-unused-function LOCAL_CLANG := true +LOCAL_CXX_STL := libc++ LOCAL_C_INCLUDES += $(LOCAL_PATH)/$(LATIN_IME_SRC_DIR) LOCAL_MODULE := liblatinime_host_unittests LOCAL_MODULE_TAGS := tests @@ -47,10 +54,13 @@ LOCAL_SRC_FILES := $(addprefix $(LATIN_IME_TEST_SRC_DIR)/, $(LATIN_IME_CORE_TEST LOCAL_STATIC_LIBRARIES += liblatinime_host_static_for_unittests include $(BUILD_HOST_NATIVE_TEST) +include $(LOCAL_PATH)/CleanupNativeFileList.mk + endif # Darwin - TODO: Remove this +endif # TARGET_BUILD_APPS + #################### Clean up the tmp vars LATINIME_HOST_OSNAME := LATIN_IME_SRC_DIR := LATIN_IME_TEST_SRC_DIR := -include $(LOCAL_PATH)/CleanupNativeFileList.mk diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp index 461d1d859..118f600bb 100644 --- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp +++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp @@ -327,8 +327,8 @@ static jint latinime_BinaryDictionary_getNextWord(JNIEnv *env, jclass clazz, static void latinime_BinaryDictionary_getWordProperty(JNIEnv *env, jclass clazz, jlong dict, jintArray word, jboolean isBeginningOfSentence, jintArray outCodePoints, - jbooleanArray outFlags, jintArray outProbabilityInfo, jobject /* outNgramPrevWordsArray */, - jobject /* outNgramPrevWordIsBeginningOfSentenceArray */, jobject outNgramTargets, + jbooleanArray outFlags, jintArray outProbabilityInfo, jobject outNgramPrevWordsArray, + jobject outNgramPrevWordIsBeginningOfSentenceArray, jobject outNgramTargets, jobject outNgramProbabilityInfo, jobject outShortcutTargets, jobject outShortcutProbabilities) { Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict); @@ -352,6 +352,7 @@ static void latinime_BinaryDictionary_getWordProperty(JNIEnv *env, jclass clazz, const WordProperty wordProperty = dictionary->getWordProperty( CodePointArrayView(wordCodePoints, codePointCount)); wordProperty.outputProperties(env, outCodePoints, outFlags, outProbabilityInfo, + outNgramPrevWordsArray, outNgramPrevWordIsBeginningOfSentenceArray, outNgramTargets, outNgramProbabilityInfo, outShortcutTargets, outShortcutProbabilities); } @@ -452,98 +453,60 @@ static bool latinime_BinaryDictionary_updateEntriesForWordWithNgramContext(JNIEn historicalInfo); } -// Returns how many language model params are processed. -static int latinime_BinaryDictionary_addMultipleDictionaryEntries(JNIEnv *env, jclass clazz, - jlong dict, jobjectArray languageModelParams, jint startIndex) { +// Returns how many input events are processed. +static int latinime_BinaryDictionary_updateEntriesForInputEvents(JNIEnv *env, jclass clazz, + jlong dict, jobjectArray inputEvents, jint startIndex) { Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict); if (!dictionary) { return 0; } - jsize languageModelParamCount = env->GetArrayLength(languageModelParams); - if (languageModelParamCount == 0 || startIndex >= languageModelParamCount) { + jsize inputEventCount = env->GetArrayLength(inputEvents); + if (inputEventCount == 0 || startIndex >= inputEventCount) { return 0; } - jobject languageModelParam = env->GetObjectArrayElement(languageModelParams, 0); - jclass languageModelParamClass = env->GetObjectClass(languageModelParam); - env->DeleteLocalRef(languageModelParam); - - jfieldID word0FieldId = env->GetFieldID(languageModelParamClass, "mWord0", "[I"); - jfieldID word1FieldId = env->GetFieldID(languageModelParamClass, "mWord1", "[I"); - jfieldID unigramProbabilityFieldId = - env->GetFieldID(languageModelParamClass, "mUnigramProbability", "I"); - jfieldID bigramProbabilityFieldId = - env->GetFieldID(languageModelParamClass, "mBigramProbability", "I"); - jfieldID timestampFieldId = - env->GetFieldID(languageModelParamClass, "mTimestamp", "I"); - jfieldID shortcutTargetFieldId = - env->GetFieldID(languageModelParamClass, "mShortcutTarget", "[I"); - jfieldID shortcutProbabilityFieldId = - env->GetFieldID(languageModelParamClass, "mShortcutProbability", "I"); - jfieldID isNotAWordFieldId = - env->GetFieldID(languageModelParamClass, "mIsNotAWord", "Z"); - jfieldID isPossiblyOffensiveFieldId = - env->GetFieldID(languageModelParamClass, "mIsPossiblyOffensive", "Z"); - env->DeleteLocalRef(languageModelParamClass); - - for (int i = startIndex; i < languageModelParamCount; ++i) { - jobject languageModelParam = env->GetObjectArrayElement(languageModelParams, i); - // languageModelParam is a set of params for word1; thus, word1 cannot be null. On the - // other hand, word0 can be null and then it means the set of params doesn't contain bigram - // information. - jintArray word0 = static_cast<jintArray>( - env->GetObjectField(languageModelParam, word0FieldId)); - jsize word0Length = word0 ? env->GetArrayLength(word0) : 0; - int word0CodePoints[word0Length]; - if (word0) { - env->GetIntArrayRegion(word0, 0, word0Length, word0CodePoints); - } - jintArray word1 = static_cast<jintArray>( - env->GetObjectField(languageModelParam, word1FieldId)); - jsize word1Length = env->GetArrayLength(word1); - int word1CodePoints[word1Length]; - env->GetIntArrayRegion(word1, 0, word1Length, word1CodePoints); - jint unigramProbability = env->GetIntField(languageModelParam, unigramProbabilityFieldId); - jint timestamp = env->GetIntField(languageModelParam, timestampFieldId); - jboolean isNotAWord = env->GetBooleanField(languageModelParam, isNotAWordFieldId); - jboolean isPossiblyOffensive = env->GetBooleanField(languageModelParam, - isPossiblyOffensiveFieldId); - jintArray shortcutTarget = static_cast<jintArray>( - env->GetObjectField(languageModelParam, shortcutTargetFieldId)); - std::vector<UnigramProperty::ShortcutProperty> shortcuts; - { - std::vector<int> shortcutTargetCodePoints; - JniDataUtils::jintarrayToVector(env, shortcutTarget, &shortcutTargetCodePoints); - if (!shortcutTargetCodePoints.empty()) { - jint shortcutProbability = - env->GetIntField(languageModelParam, shortcutProbabilityFieldId); - shortcuts.emplace_back(std::move(shortcutTargetCodePoints), shortcutProbability); - } - } + jobject inputEvent = env->GetObjectArrayElement(inputEvents, 0); + jclass wordInputEventClass = env->GetObjectClass(inputEvent); + env->DeleteLocalRef(inputEvent); + + jfieldID targetWordFieldId = env->GetFieldID(wordInputEventClass, "mTargetWord", "[I"); + jfieldID prevWordCountFieldId = env->GetFieldID(wordInputEventClass, "mPrevWordsCount", "I"); + jfieldID prevWordArrayFieldId = env->GetFieldID(wordInputEventClass, "mPrevWordArray", "[[I"); + jfieldID isPrevWordBoSArrayFieldId = + env->GetFieldID(wordInputEventClass, "mIsPrevWordBeginningOfSentenceArray", "[Z"); + jfieldID isValidFieldId = env->GetFieldID(wordInputEventClass, "mIsValid", "Z"); + jfieldID timestampFieldId = env->GetFieldID(wordInputEventClass, "mTimestamp", "I"); + env->DeleteLocalRef(wordInputEventClass); + + for (int i = startIndex; i < inputEventCount; ++i) { + jobject inputEvent = env->GetObjectArrayElement(inputEvents, i); + jintArray targetWord = static_cast<jintArray>( + env->GetObjectField(inputEvent, targetWordFieldId)); + jsize wordLength = env->GetArrayLength(targetWord); + int wordCodePoints[wordLength]; + env->GetIntArrayRegion(targetWord, 0, wordLength, wordCodePoints); + env->DeleteLocalRef(targetWord); + + jint prevWordCount = env->GetIntField(inputEvent, prevWordCountFieldId); + jobjectArray prevWordArray = + static_cast<jobjectArray>(env->GetObjectField(inputEvent, prevWordArrayFieldId)); + jbooleanArray isPrevWordBeginningOfSentenceArray = static_cast<jbooleanArray>( + env->GetObjectField(inputEvent, isPrevWordBoSArrayFieldId)); + jboolean isValid = env->GetBooleanField(inputEvent, isValidFieldId); + jint timestamp = env->GetIntField(inputEvent, timestampFieldId); + const NgramContext ngramContext = JniDataUtils::constructNgramContext(env, + prevWordArray, isPrevWordBeginningOfSentenceArray, prevWordCount); // Use 1 for count to indicate the word has inputted. - const UnigramProperty unigramProperty(false /* isBeginningOfSentence */, isNotAWord, - isPossiblyOffensive, unigramProbability, - HistoricalInfo(timestamp, 0 /* level */, 1 /* count */), std::move(shortcuts)); - dictionary->addUnigramEntry(CodePointArrayView(word1CodePoints, word1Length), - &unigramProperty); - if (word0) { - jint bigramProbability = env->GetIntField(languageModelParam, bigramProbabilityFieldId); - // Use 1 for count to indicate the bigram has inputted. - const NgramContext ngramContext(word0CodePoints, word0Length, - false /* isBeginningOfSentence */); - const NgramProperty ngramProperty(ngramContext, - CodePointArrayView(word1CodePoints, word1Length).toVector(), - bigramProbability, HistoricalInfo(timestamp, 0 /* level */, 1 /* count */)); - dictionary->addNgramEntry(&ngramProperty); - } + dictionary->updateEntriesForWordWithNgramContext(&ngramContext, + CodePointArrayView(wordCodePoints, wordLength), isValid, + HistoricalInfo(timestamp, 0 /* level */, 1 /* count */)); if (dictionary->needsToRunGC(true /* mindsBlockByGC */)) { return i + 1; } - env->DeleteLocalRef(word0); - env->DeleteLocalRef(word1); - env->DeleteLocalRef(shortcutTarget); - env->DeleteLocalRef(languageModelParam); + env->DeleteLocalRef(prevWordArray); + env->DeleteLocalRef(isPrevWordBeginningOfSentenceArray); + env->DeleteLocalRef(inputEvent); } - return languageModelParamCount; + return inputEventCount; } static jstring latinime_BinaryDictionary_getProperty(JNIEnv *env, jclass clazz, jlong dict, @@ -753,10 +716,10 @@ static const JNINativeMethod sMethods[] = { reinterpret_cast<void *>(latinime_BinaryDictionary_updateEntriesForWordWithNgramContext) }, { - const_cast<char *>("addMultipleDictionaryEntriesNative"), + const_cast<char *>("updateEntriesForInputEventsNative"), const_cast<char *>( - "(J[Lcom/android/inputmethod/latin/utils/LanguageModelParam;I)I"), - reinterpret_cast<void *>(latinime_BinaryDictionary_addMultipleDictionaryEntries) + "(J[Lcom/android/inputmethod/latin/utils/WordInputEventForPersonalization;I)I"), + reinterpret_cast<void *>(latinime_BinaryDictionary_updateEntriesForInputEvents) }, { const_cast<char *>("getPropertyNative"), diff --git a/native/jni/run-tests.sh b/native/jni/run-tests.sh index 3da45270d..a7fa82d9b 100755 --- a/native/jni/run-tests.sh +++ b/native/jni/run-tests.sh @@ -48,6 +48,13 @@ if [[ $show_usage == yes ]]; then if [[ ${BASH_SOURCE[0]} != $0 ]]; then return; else exit 1; fi fi +# Host build is never supported in unbundled (NDK/tapas) build +if [[ $enable_host_test == yes && -n $TARGET_BUILD_APPS ]]; then + echo "Host build is never supported in tapas build." 1>&2 + echo "Use lunch command instead." 1>&2 + if [[ ${BASH_SOURCE[0]} != $0 ]]; then return; else exit 1; fi +fi + target_test_name=liblatinime_target_unittests host_test_name=liblatinime_host_unittests diff --git a/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp b/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp index 7d2898b7a..ea438922f 100644 --- a/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp +++ b/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp @@ -74,8 +74,9 @@ namespace latinime { } const WordAttributes wordAttributes = dictionaryStructurePolicy->getWordAttributesInContext( dicNode->getPrevWordIds(), dicNode->getWordId(), multiBigramMap); - if (dicNode->hasMultipleWords() - && (wordAttributes.isBlacklisted() || wordAttributes.isNotAWord())) { + if (wordAttributes.getProbability() == NOT_A_PROBABILITY + || (dicNode->hasMultipleWords() + && (wordAttributes.isBlacklisted() || wordAttributes.isNotAWord()))) { return static_cast<float>(MAX_VALUE_FOR_WEIGHTING); } // TODO: This equation to calculate the improbability looks unreasonable. Investigate this. diff --git a/native/jni/src/suggest/core/dictionary/property/word_property.cpp b/native/jni/src/suggest/core/dictionary/property/word_property.cpp index a707f1ba2..019f0880f 100644 --- a/native/jni/src/suggest/core/dictionary/property/word_property.cpp +++ b/native/jni/src/suggest/core/dictionary/property/word_property.cpp @@ -22,8 +22,9 @@ namespace latinime { void WordProperty::outputProperties(JNIEnv *const env, jintArray outCodePoints, - jbooleanArray outFlags, jintArray outProbabilityInfo, jobject outBigramTargets, - jobject outBigramProbabilities, jobject outShortcutTargets, + jbooleanArray outFlags, jintArray outProbabilityInfo, + jobject outNgramPrevWordsArray, jobject outNgramPrevWordIsBeginningOfSentenceArray, + jobject outNgramTargets, jobject outNgramProbabilities, jobject outShortcutTargets, jobject outShortcutProbabilities) const { JniDataUtils::outputCodePoints(env, outCodePoints, 0 /* start */, MAX_WORD_LENGTH /* maxLength */, mCodePoints.data(), mCodePoints.size(), @@ -43,16 +44,39 @@ void WordProperty::outputProperties(JNIEnv *const env, jintArray outCodePoints, jclass arrayListClass = env->FindClass("java/util/ArrayList"); jmethodID addMethodId = env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z"); - // Output bigrams. - // TODO: Support n-gram + // Output ngrams. + jclass intArrayClass = env->FindClass("[I"); for (const auto &ngramProperty : mNgrams) { - const std::vector<int> *const word1CodePoints = ngramProperty.getTargetCodePoints(); - jintArray bigramWord1CodePointArray = env->NewIntArray(word1CodePoints->size()); - JniDataUtils::outputCodePoints(env, bigramWord1CodePointArray, 0 /* start */, - word1CodePoints->size(), word1CodePoints->data(), word1CodePoints->size(), - false /* needsNullTermination */); - env->CallBooleanMethod(outBigramTargets, addMethodId, bigramWord1CodePointArray); - env->DeleteLocalRef(bigramWord1CodePointArray); + const NgramContext *const ngramContext = ngramProperty.getNgramContext(); + jobjectArray prevWordWordCodePointsArray = env->NewObjectArray( + ngramContext->getPrevWordCount(), intArrayClass, nullptr); + jbooleanArray prevWordIsBeginningOfSentenceArray = + env->NewBooleanArray(ngramContext->getPrevWordCount()); + for (size_t i = 0; i < ngramContext->getPrevWordCount(); ++i) { + const CodePointArrayView codePoints = ngramContext->getNthPrevWordCodePoints(i + 1); + jintArray prevWordCodePoints = env->NewIntArray(codePoints.size()); + JniDataUtils::outputCodePoints(env, prevWordCodePoints, 0 /* start */, + codePoints.size(), codePoints.data(), codePoints.size(), + false /* needsNullTermination */); + env->SetObjectArrayElement(prevWordWordCodePointsArray, i, prevWordCodePoints); + env->DeleteLocalRef(prevWordCodePoints); + JniDataUtils::putBooleanToArray(env, prevWordIsBeginningOfSentenceArray, i, + ngramContext->isNthPrevWordBeginningOfSentence(i + 1)); + } + env->CallBooleanMethod(outNgramPrevWordsArray, addMethodId, prevWordWordCodePointsArray); + env->CallBooleanMethod(outNgramPrevWordIsBeginningOfSentenceArray, addMethodId, + prevWordIsBeginningOfSentenceArray); + env->DeleteLocalRef(prevWordWordCodePointsArray); + env->DeleteLocalRef(prevWordIsBeginningOfSentenceArray); + + const std::vector<int> *const targetWordCodePoints = ngramProperty.getTargetCodePoints(); + jintArray targetWordCodePointArray = env->NewIntArray(targetWordCodePoints->size()); + JniDataUtils::outputCodePoints(env, targetWordCodePointArray, 0 /* start */, + targetWordCodePoints->size(), targetWordCodePoints->data(), + targetWordCodePoints->size(), false /* needsNullTermination */); + env->CallBooleanMethod(outNgramTargets, addMethodId, targetWordCodePointArray); + env->DeleteLocalRef(targetWordCodePointArray); + const HistoricalInfo &ngramHistoricalInfo = ngramProperty.getHistoricalInfo(); int bigramProbabilityInfo[] = {ngramProperty.getProbability(), ngramHistoricalInfo.getTimestamp(), ngramHistoricalInfo.getLevel(), @@ -60,7 +84,7 @@ void WordProperty::outputProperties(JNIEnv *const env, jintArray outCodePoints, jintArray bigramProbabilityInfoArray = env->NewIntArray(NELEMS(bigramProbabilityInfo)); env->SetIntArrayRegion(bigramProbabilityInfoArray, 0 /* start */, NELEMS(bigramProbabilityInfo), bigramProbabilityInfo); - env->CallBooleanMethod(outBigramProbabilities, addMethodId, bigramProbabilityInfoArray); + env->CallBooleanMethod(outNgramProbabilities, addMethodId, bigramProbabilityInfoArray); env->DeleteLocalRef(bigramProbabilityInfoArray); } diff --git a/native/jni/src/suggest/core/dictionary/property/word_property.h b/native/jni/src/suggest/core/dictionary/property/word_property.h index 01b8987b5..b5314faaa 100644 --- a/native/jni/src/suggest/core/dictionary/property/word_property.h +++ b/native/jni/src/suggest/core/dictionary/property/word_property.h @@ -39,8 +39,10 @@ class WordProperty { mNgrams(*ngrams) {} void outputProperties(JNIEnv *const env, jintArray outCodePoints, jbooleanArray outFlags, - jintArray outProbabilityInfo, jobject outBigramTargets, jobject outBigramProbabilities, - jobject outShortcutTargets, jobject outShortcutProbabilities) const; + jintArray outProbabilityInfo, jobject outNgramPrevWordsArray, + jobject outNgramPrevWordIsBeginningOfSentenceArray, jobject outNgramTargets, + jobject outNgramProbabilities, jobject outShortcutTargets, + jobject outShortcutProbabilities) const; const UnigramProperty *getUnigramProperty() const { return &mUnigramProperty; diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.cpp index b96290437..509bd683b 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.cpp @@ -90,8 +90,8 @@ const WordAttributes LanguageModelDictContent::getWordAttributes(const WordIdArr // TODO: Some flags in unigramProbabilityEntry should be overwritten by flags in // probabilityEntry. const ProbabilityEntry unigramProbabilityEntry = getProbabilityEntry(wordId); - return WordAttributes(probability, unigramProbabilityEntry.isNotAWord(), - unigramProbabilityEntry.isBlacklisted(), + return WordAttributes(probability, unigramProbabilityEntry.isBlacklisted(), + unigramProbabilityEntry.isNotAWord(), unigramProbabilityEntry.isPossiblyOffensive()); } // Cannot find the word. diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp index 193326d82..249d822b2 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp @@ -488,9 +488,6 @@ const WordProperty Ver4PatriciaTriePolicy::getWordProperty( AKLOGE("getWordProperty is called for invalid word."); return WordProperty(); } - const int ptNodePos = - mBuffers->getTerminalPositionLookupTable()->getTerminalPtNodePosition(wordId); - const PtNodeParams ptNodeParams = mNodeReader.fetchPtNodeParamsInBufferFromPtNodePos(ptNodePos); const LanguageModelDictContent *const languageModelDictContent = mBuffers->getLanguageModelDictContent(); // Fetch ngram information. @@ -541,12 +538,13 @@ const WordProperty Ver4PatriciaTriePolicy::getWordProperty( shortcutProbability); } } - const ProbabilityEntry probabilityEntry = languageModelDictContent->getProbabilityEntry( - ptNodeParams.getTerminalId()); + const WordAttributes wordAttributes = languageModelDictContent->getWordAttributes( + WordIdArrayView(), wordId, mHeaderPolicy); + const ProbabilityEntry probabilityEntry = languageModelDictContent->getProbabilityEntry(wordId); const HistoricalInfo *const historicalInfo = probabilityEntry.getHistoricalInfo(); const UnigramProperty unigramProperty(probabilityEntry.representsBeginningOfSentence(), - probabilityEntry.isNotAWord(), probabilityEntry.isBlacklisted(), - probabilityEntry.isPossiblyOffensive(), probabilityEntry.getProbability(), + wordAttributes.isNotAWord(), wordAttributes.isBlacklisted(), + wordAttributes.isPossiblyOffensive(), wordAttributes.getProbability(), *historicalInfo, std::move(shortcuts)); return WordProperty(wordCodePoints.toVector(), &unigramProperty, &ngrams); } diff --git a/native/jni/src/utils/jni_data_utils.h b/native/jni/src/utils/jni_data_utils.h index 25cc41742..a259e1cd0 100644 --- a/native/jni/src/utils/jni_data_utils.h +++ b/native/jni/src/utils/jni_data_utils.h @@ -50,6 +50,7 @@ class JniDataUtils { const jsize keyUtf8Length = env->GetStringUTFLength(keyString); char keyChars[keyUtf8Length + 1]; env->GetStringUTFRegion(keyString, 0, env->GetStringLength(keyString), keyChars); + env->DeleteLocalRef(keyString); keyChars[keyUtf8Length] = '\0'; DictionaryHeaderStructurePolicy::AttributeMap::key_type key; HeaderReadWriteUtils::insertCharactersIntoVector(keyChars, &key); @@ -59,6 +60,7 @@ class JniDataUtils { const jsize valueUtf8Length = env->GetStringUTFLength(valueString); char valueChars[valueUtf8Length + 1]; env->GetStringUTFRegion(valueString, 0, env->GetStringLength(valueString), valueChars); + env->DeleteLocalRef(valueString); valueChars[valueUtf8Length] = '\0'; DictionaryHeaderStructurePolicy::AttributeMap::mapped_type value; HeaderReadWriteUtils::insertCharactersIntoVector(valueChars, &value); @@ -113,6 +115,7 @@ class JniDataUtils { continue; } env->GetIntArrayRegion(prevWord, 0, prevWordLength, prevWordCodePoints[i]); + env->DeleteLocalRef(prevWord); prevWordCodePointCount[i] = prevWordLength; jboolean isBeginningOfSentenceBoolean = JNI_FALSE; env->GetBooleanArrayRegion(isBeginningOfSentenceArray, i, 1 /* len */, |