From e137ec0a91cf93b0a99fd1e1556ee835d026f731 Mon Sep 17 00:00:00 2001 From: Keisuke Kuroyanagi Date: Fri, 7 Mar 2014 19:36:19 +0900 Subject: [PATCH] Introduce SuggestionResults and use it for predictions. Bug: 8187060 Bug: 13333066 Change-Id: I1ead897024508b7e40fbd93af7d14bfe74b93826 --- .../inputmethod/latin/BinaryDictionary.java | 12 +-- native/jni/NativeFileList.mk | 4 +- ...oid_inputmethod_latin_BinaryDictionary.cpp | 56 ++++++++----- .../core/dictionary/bigram_dictionary.cpp | 77 ++--------------- .../core/dictionary/bigram_dictionary.h | 7 +- .../suggest/core/dictionary/dictionary.cpp | 9 +- .../src/suggest/core/dictionary/dictionary.h | 5 +- .../src/suggest/core/result/suggested_word.h | 83 +++++++++++++++++++ .../core/result/suggestion_results.cpp | 77 +++++++++++++++++ .../suggest/core/result/suggestion_results.h | 53 ++++++++++++ 10 files changed, 274 insertions(+), 109 deletions(-) create mode 100644 native/jni/src/suggest/core/result/suggested_word.h create mode 100644 native/jni/src/suggest/core/result/suggestion_results.cpp create mode 100644 native/jni/src/suggest/core/result/suggestion_results.h diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index a3a329a71..f659b3f79 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -87,6 +87,7 @@ public final class BinaryDictionary extends Dictionary { private final String mDictFilePath; private final boolean mIsUpdatable; private final int[] mInputCodePoints = new int[MAX_WORD_LENGTH]; + private final int[] mOutputSuggestionCount = new int[1]; private final int[] mOutputCodePoints = new int[MAX_WORD_LENGTH * MAX_RESULTS]; private final int[] mSpaceIndices = new int[MAX_RESULTS]; private final int[] mOutputScores = new int[MAX_RESULTS]; @@ -158,10 +159,10 @@ public final class BinaryDictionary extends Dictionary { ArrayList outBigramTargets, ArrayList outBigramProbabilityInfo, ArrayList outShortcutTargets, ArrayList outShortcutProbabilities); private static native int getNextWordNative(long dict, int token, int[] outCodePoints); - private static native int getSuggestionsNative(long dict, long proximityInfo, + private static native void getSuggestionsNative(long dict, long proximityInfo, long traverseSession, int[] xCoordinates, int[] yCoordinates, int[] times, int[] pointerIds, int[] inputCodePoints, int inputSize, int commitPoint, - int[] suggestOptions, int[] prevWordCodePointArray, + int[] suggestOptions, int[] prevWordCodePointArray, int[] outputSuggestionCount, int[] outputCodePoints, int[] outputScores, int[] outputIndices, int[] outputTypes, int[] outputAutoCommitFirstWordConfidence); private static native void addUnigramWordNative(long dict, int[] word, int probability, @@ -258,12 +259,13 @@ public final class BinaryDictionary extends Dictionary { mNativeSuggestOptions.setIsGesture(isGesture); mNativeSuggestOptions.setAdditionalFeaturesOptions(additionalFeaturesOptions); // proximityInfo and/or prevWordForBigrams may not be null. - final int count = getSuggestionsNative(mNativeDict, proximityInfo.getNativeProximityInfo(), + getSuggestionsNative(mNativeDict, proximityInfo.getNativeProximityInfo(), getTraverseSession(sessionId).getSession(), ips.getXCoordinates(), ips.getYCoordinates(), ips.getTimes(), ips.getPointerIds(), mInputCodePoints, inputSize, 0 /* commitPoint */, mNativeSuggestOptions.getOptions(), - prevWordCodePointArray, mOutputCodePoints, mOutputScores, mSpaceIndices, - mOutputTypes, mOutputAutoCommitFirstWordConfidence); + prevWordCodePointArray, mOutputSuggestionCount, mOutputCodePoints, mOutputScores, + mSpaceIndices, mOutputTypes, mOutputAutoCommitFirstWordConfidence); + final int count = mOutputSuggestionCount[0]; final ArrayList suggestions = CollectionUtils.newArrayList(); for (int j = 0; j < count; ++j) { final int start = j * MAX_WORD_LENGTH; diff --git a/native/jni/NativeFileList.mk b/native/jni/NativeFileList.mk index 1f5824608..2ee4caa42 100644 --- a/native/jni/NativeFileList.mk +++ b/native/jni/NativeFileList.mk @@ -40,8 +40,10 @@ LATIN_IME_CORE_SRC_FILES := \ proximity_info_state.cpp \ proximity_info_state_utils.cpp) \ suggest/core/policy/weighting.cpp \ - suggest/core/result/suggestions_output_utils.cpp \ suggest/core/session/dic_traverse_session.cpp \ + $(addprefix suggest/core/result/, \ + suggestion_results.cpp \ + suggestions_output_utils.cpp) \ $(addprefix suggest/policyimpl/dictionary/, \ header/header_policy.cpp \ header/header_read_write_utils.cpp \ diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp index 5b972837f..eec354abc 100644 --- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp +++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp @@ -25,6 +25,7 @@ #include "jni_common.h" #include "suggest/core/dictionary/dictionary.h" #include "suggest/core/dictionary/word_property.h" +#include "suggest/core/result/suggestion_results.h" #include "suggest/core/suggest_options.h" #include "suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.h" #include "utils/char_utils.h" @@ -139,15 +140,20 @@ static int latinime_BinaryDictionary_getFormatVersion(JNIEnv *env, jclass clazz, return headerPolicy->getFormatVersionNumber(); } -static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jclass clazz, jlong dict, +static void latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jclass clazz, jlong dict, jlong proximityInfo, jlong dicTraverseSession, jintArray xCoordinatesArray, jintArray yCoordinatesArray, jintArray timesArray, jintArray pointerIdsArray, jintArray inputCodePointsArray, jint inputSize, jint commitPoint, jintArray suggestOptions, - jintArray prevWordCodePointsForBigrams, jintArray outputCodePointsArray, - jintArray scoresArray, jintArray spaceIndicesArray, jintArray outputTypesArray, - jintArray outputAutoCommitFirstWordConfidenceArray) { + jintArray prevWordCodePointsForBigrams, jintArray outSuggestionCount, + jintArray outCodePointsArray, jintArray outScoresArray, jintArray outSpaceIndicesArray, + jintArray outTypesArray, jintArray outAutoCommitFirstWordConfidenceArray) { Dictionary *dictionary = reinterpret_cast(dict); - if (!dictionary) return 0; + // Assign 0 to outSuggestionCount here in case of returning earlier in this method. + int count = 0; + env->SetIntArrayRegion(outSuggestionCount, 0, 1 /* len */, &count); + if (!dictionary) { + return; + } ProximityInfo *pInfo = reinterpret_cast(proximityInfo); DicTraverseSession *traverseSession = reinterpret_cast(dicTraverseSession); @@ -181,26 +187,26 @@ static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jclass clazz, j // Output values /* By the way, let's check the output array length here to make sure */ - const jsize outputCodePointsLength = env->GetArrayLength(outputCodePointsArray); + const jsize outputCodePointsLength = env->GetArrayLength(outCodePointsArray); if (outputCodePointsLength != (MAX_WORD_LENGTH * MAX_RESULTS)) { AKLOGE("Invalid outputCodePointsLength: %d", outputCodePointsLength); ASSERT(false); - return 0; + return; } - const jsize scoresLength = env->GetArrayLength(scoresArray); + const jsize scoresLength = env->GetArrayLength(outScoresArray); if (scoresLength != MAX_RESULTS) { AKLOGE("Invalid scoresLength: %d", scoresLength); ASSERT(false); - return 0; + return; } int outputCodePoints[outputCodePointsLength]; int scores[scoresLength]; - const jsize spaceIndicesLength = env->GetArrayLength(spaceIndicesArray); + const jsize spaceIndicesLength = env->GetArrayLength(outSpaceIndicesArray); int spaceIndices[spaceIndicesLength]; - const jsize outputTypesLength = env->GetArrayLength(outputTypesArray); + const jsize outputTypesLength = env->GetArrayLength(outTypesArray); int outputTypes[outputTypesLength]; const jsize outputAutoCommitFirstWordConfidenceLength = - env->GetArrayLength(outputAutoCommitFirstWordConfidenceArray); + env->GetArrayLength(outAutoCommitFirstWordConfidenceArray); // We only use the first result, as obviously we will only ever autocommit the first one ASSERT(outputAutoCommitFirstWordConfidenceLength == 1); int outputAutoCommitFirstWordConfidence[outputAutoCommitFirstWordConfidenceLength]; @@ -210,26 +216,30 @@ static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jclass clazz, j memset(outputTypes, 0, sizeof(outputTypes)); memset(outputAutoCommitFirstWordConfidence, 0, sizeof(outputAutoCommitFirstWordConfidence)); - int count; if (givenSuggestOptions.isGesture() || inputSize > 0) { + // TODO: Use SuggestionResults to return suggestions. count = dictionary->getSuggestions(pInfo, traverseSession, xCoordinates, yCoordinates, times, pointerIds, inputCodePoints, inputSize, prevWordCodePoints, prevWordCodePointsLength, commitPoint, &givenSuggestOptions, outputCodePoints, scores, spaceIndices, outputTypes, outputAutoCommitFirstWordConfidence); } else { - count = dictionary->getBigrams(prevWordCodePoints, prevWordCodePointsLength, - outputCodePoints, scores, outputTypes); + SuggestionResults suggestionResults(MAX_RESULTS); + dictionary->getPredictions(prevWordCodePoints, prevWordCodePointsLength, + &suggestionResults); + suggestionResults.outputSuggestions(env, outSuggestionCount, outCodePointsArray, + outScoresArray, outSpaceIndicesArray, outTypesArray, + outAutoCommitFirstWordConfidenceArray); + return; } // Copy back the output values - env->SetIntArrayRegion(outputCodePointsArray, 0, outputCodePointsLength, outputCodePoints); - env->SetIntArrayRegion(scoresArray, 0, scoresLength, scores); - env->SetIntArrayRegion(spaceIndicesArray, 0, spaceIndicesLength, spaceIndices); - env->SetIntArrayRegion(outputTypesArray, 0, outputTypesLength, outputTypes); - env->SetIntArrayRegion(outputAutoCommitFirstWordConfidenceArray, 0, + env->SetIntArrayRegion(outSuggestionCount, 0, 1 /* len */, &count); + env->SetIntArrayRegion(outCodePointsArray, 0, outputCodePointsLength, outputCodePoints); + env->SetIntArrayRegion(outScoresArray, 0, scoresLength, scores); + env->SetIntArrayRegion(outSpaceIndicesArray, 0, spaceIndicesLength, spaceIndices); + env->SetIntArrayRegion(outTypesArray, 0, outputTypesLength, outputTypes); + env->SetIntArrayRegion(outAutoCommitFirstWordConfidenceArray, 0, outputAutoCommitFirstWordConfidenceLength, outputAutoCommitFirstWordConfidence); - - return count; } static jint latinime_BinaryDictionary_getProbability(JNIEnv *env, jclass clazz, jlong dict, @@ -496,7 +506,7 @@ static const JNINativeMethod sMethods[] = { }, { const_cast("getSuggestionsNative"), - const_cast("(JJJ[I[I[I[I[III[I[I[I[I[I[I[I)I"), + const_cast("(JJJ[I[I[I[I[III[I[I[I[I[I[I[I[I)V"), reinterpret_cast(latinime_BinaryDictionary_getSuggestions) }, { diff --git a/native/jni/src/suggest/core/dictionary/bigram_dictionary.cpp b/native/jni/src/suggest/core/dictionary/bigram_dictionary.cpp index 0859df423..f793363a8 100644 --- a/native/jni/src/suggest/core/dictionary/bigram_dictionary.cpp +++ b/native/jni/src/suggest/core/dictionary/bigram_dictionary.cpp @@ -25,6 +25,7 @@ #include "suggest/core/dictionary/binary_dictionary_bigrams_iterator.h" #include "suggest/core/dictionary/dictionary.h" #include "suggest/core/policy/dictionary_structure_with_buffer_policy.h" +#include "suggest/core/result/suggestion_results.h" #include "utils/char_utils.h" namespace latinime { @@ -40,71 +41,13 @@ BigramDictionary::BigramDictionary( BigramDictionary::~BigramDictionary() { } -void BigramDictionary::addWordBigram(int *word, int length, int probability, int *bigramProbability, - int *bigramCodePoints, int *outputTypes) const { - if (length >= MAX_WORD_LENGTH) { - length = MAX_WORD_LENGTH - 1; - } - word[length] = 0; - if (DEBUG_DICT_FULL) { -#ifdef FLAG_DBG - char s[length + 1]; - for (int i = 0; i <= length; i++) s[i] = static_cast(word[i]); - AKLOGI("Bigram: Found word = %s, freq = %d :", s, probability); -#endif - } - - // Find the right insertion point - int insertAt = 0; - while (insertAt < MAX_RESULTS) { - if (probability > bigramProbability[insertAt] || (bigramProbability[insertAt] == probability - && length < CharUtils::getCodePointCount(MAX_WORD_LENGTH, - bigramCodePoints + insertAt * MAX_WORD_LENGTH))) { - break; - } - insertAt++; - } - if (DEBUG_DICT_FULL) { - AKLOGI("Bigram: InsertAt -> %d MAX_RESULTS: %d", insertAt, MAX_RESULTS); - } - if (insertAt >= MAX_RESULTS) { - return; - } - // Shift result buffers to insert the new entry. - memmove(bigramProbability + (insertAt + 1), bigramProbability + insertAt, - (MAX_RESULTS - insertAt - 1) * sizeof(bigramProbability[0])); - memmove(outputTypes + (insertAt + 1), outputTypes + insertAt, - (MAX_RESULTS - insertAt - 1) * sizeof(outputTypes[0])); - memmove(bigramCodePoints + (insertAt + 1) * MAX_WORD_LENGTH, - bigramCodePoints + insertAt * MAX_WORD_LENGTH, - (MAX_RESULTS - insertAt - 1) * sizeof(bigramCodePoints[0]) * MAX_WORD_LENGTH); - // Put the result. - bigramProbability[insertAt] = probability; - outputTypes[insertAt] = Dictionary::KIND_PREDICTION; - int *dest = bigramCodePoints + insertAt * MAX_WORD_LENGTH; - while (length--) { - *dest++ = *word++; - } - *dest = 0; // NULL terminate - if (DEBUG_DICT_FULL) { - AKLOGI("Bigram: Added word at %d", insertAt); - } -} - /* Parameters : * prevWord: the word before, the one for which we need to look up bigrams. * prevWordLength: its length. - * outBigramCodePoints: an array for output, at the same format as outwords for getSuggestions. - * outBigramProbability: an array to output frequencies. - * outputTypes: an array to output types. - * This method returns the number of bigrams this word has, for backward compatibility. + * outSuggestionResults: SuggestionResults to put the predictions. */ -int BigramDictionary::getPredictions(const int *prevWord, const int prevWordLength, - int *const outBigramCodePoints, int *const outBigramProbability, - int *const outputTypes) const { - // TODO: remove unused arguments, and refrain from storing stuff in members of this class - // TODO: have "in" arguments before "out" ones, and make out args explicit in the name - +void BigramDictionary::getPredictions(const int *prevWord, const int prevWordLength, + SuggestionResults *const outSuggestionResults) const { int pos = getBigramListPositionForWord(prevWord, prevWordLength, false /* forceLowerCaseSearch */); // getBigramListPositionForWord returns 0 if this word isn't in the dictionary or has no bigrams @@ -114,11 +57,10 @@ int BigramDictionary::getPredictions(const int *prevWord, const int prevWordLeng true /* forceLowerCaseSearch */); } // If still no bigrams, we really don't have them! - if (NOT_A_DICT_POS == pos) return 0; + if (NOT_A_DICT_POS == pos) return; - int bigramCount = 0; int unigramProbability = 0; - int bigramBuffer[MAX_WORD_LENGTH]; + int bigramCodePoints[MAX_WORD_LENGTH]; BinaryDictionaryBigramsIterator bigramsIt( mDictionaryStructurePolicy->getBigramsStructurePolicy(), pos); while (bigramsIt.hasNext()) { @@ -128,7 +70,7 @@ int BigramDictionary::getPredictions(const int *prevWord, const int prevWordLeng } const int codePointCount = mDictionaryStructurePolicy-> getCodePointsAndProbabilityAndReturnCodePointCount(bigramsIt.getBigramPos(), - MAX_WORD_LENGTH, bigramBuffer, &unigramProbability); + MAX_WORD_LENGTH, bigramCodePoints, &unigramProbability); if (codePointCount <= 0) { continue; } @@ -139,11 +81,8 @@ int BigramDictionary::getPredictions(const int *prevWord, const int prevWordLeng // here, but it can't get too bad. const int probability = mDictionaryStructurePolicy->getProbability( unigramProbability, bigramsIt.getProbability()); - addWordBigram(bigramBuffer, codePointCount, probability, outBigramProbability, - outBigramCodePoints, outputTypes); - ++bigramCount; + outSuggestionResults->addPrediction(bigramCodePoints, codePointCount, probability); } - return std::min(bigramCount, MAX_RESULTS); } // Returns a pointer to the start of the bigram list. diff --git a/native/jni/src/suggest/core/dictionary/bigram_dictionary.h b/native/jni/src/suggest/core/dictionary/bigram_dictionary.h index 8af7ee75d..12aaf20d3 100644 --- a/native/jni/src/suggest/core/dictionary/bigram_dictionary.h +++ b/native/jni/src/suggest/core/dictionary/bigram_dictionary.h @@ -22,21 +22,20 @@ namespace latinime { class DictionaryStructureWithBufferPolicy; +class SuggestionResults; class BigramDictionary { public: BigramDictionary(const DictionaryStructureWithBufferPolicy *const dictionaryStructurePolicy); - int getPredictions(const int *word, int length, int *outBigramCodePoints, - int *outBigramProbability, int *outputTypes) const; + void getPredictions(const int *word, int length, + SuggestionResults *const outSuggestionResults) const; int getBigramProbability(const int *word1, int length1, const int *word2, int length2) const; ~BigramDictionary(); private: DISALLOW_IMPLICIT_CONSTRUCTORS(BigramDictionary); - void addWordBigram(int *word, int length, int probability, int *bigramProbability, - int *bigramCodePoints, int *outputTypes) const; int getBigramListPositionForWord(const int *prevWord, const int prevWordLength, const bool forceLowerCaseSearch) const; diff --git a/native/jni/src/suggest/core/dictionary/dictionary.cpp b/native/jni/src/suggest/core/dictionary/dictionary.cpp index 59a8a5500..ffa96e167 100644 --- a/native/jni/src/suggest/core/dictionary/dictionary.cpp +++ b/native/jni/src/suggest/core/dictionary/dictionary.cpp @@ -74,12 +74,11 @@ int Dictionary::getSuggestions(ProximityInfo *proximityInfo, DicTraverseSession } } -int Dictionary::getBigrams(const int *word, int length, int *outWords, int *outputScores, - int *outputTypes) const { +void Dictionary::getPredictions(const int *word, int length, + SuggestionResults *const outSuggestionResults) const { TimeKeeper::setCurrentTime(); - if (length <= 0) return 0; - return mBigramDictionary->getPredictions(word, length, outWords, outputScores, - outputTypes); + if (length <= 0) return; + mBigramDictionary->getPredictions(word, length, outSuggestionResults); } int Dictionary::getProbability(const int *word, int length) const { diff --git a/native/jni/src/suggest/core/dictionary/dictionary.h b/native/jni/src/suggest/core/dictionary/dictionary.h index a7f19c9e6..2dea9fff8 100644 --- a/native/jni/src/suggest/core/dictionary/dictionary.h +++ b/native/jni/src/suggest/core/dictionary/dictionary.h @@ -33,6 +33,7 @@ namespace latinime { class DictionaryStructureWithBufferPolicy; class DicTraverseSession; class ProximityInfo; +class SuggestionResults; class SuggestOptions; class WordProperty; @@ -67,8 +68,8 @@ class Dictionary { const SuggestOptions *const suggestOptions, int *outWords, int *outputScores, int *spaceIndices, int *outputTypes, int *outputAutoCommitFirstWordConfidence) const; - int getBigrams(const int *word, int length, int *outWords, int *outputScores, - int *outputTypes) const; + void getPredictions(const int *word, int length, + SuggestionResults *const outSuggestionResults) const; int getProbability(const int *word, int length) const; diff --git a/native/jni/src/suggest/core/result/suggested_word.h b/native/jni/src/suggest/core/result/suggested_word.h new file mode 100644 index 000000000..48b29d6a6 --- /dev/null +++ b/native/jni/src/suggest/core/result/suggested_word.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LATINIME_SUGGESTED_WORD_H +#define LATINIME_SUGGESTED_WORD_H + +#include + +#include "defines.h" +#include "suggest/core/dictionary/dictionary.h" + +namespace latinime { + +class SuggestedWord { + public: + class Comparator { + public: + bool operator()(const SuggestedWord &left, const SuggestedWord &right) { + if (left.getScore() != right.getScore()) { + return left.getScore() < right.getScore(); + } + return left.getCodePointCount() > right.getCodePointCount(); + } + + private: + DISALLOW_ASSIGNMENT_OPERATOR(Comparator); + }; + + SuggestedWord(const int *const codePoints, const int codePointCount, + const int score, const int type, const int indexToPartialCommit, + const int autoCommitFirstWordConfidence) + : mCodePoints(codePoints, codePoints + codePointCount), mScore(score), + mType(type), mIndexToPartialCommit(indexToPartialCommit), + mAutoCommitFirstWordConfidence(autoCommitFirstWordConfidence) {} + + const int *getCodePoint() const { + return &mCodePoints.at(0); + } + + int getCodePointCount() const { + return mCodePoints.size(); + } + + int getScore() const { + return mScore; + } + + int getType() const { + return mType; + } + + int getIndexToPartialCommit() const { + return mIndexToPartialCommit; + } + + int getAutoCommitFirstWordConfidence() const { + return mAutoCommitFirstWordConfidence; + } + + private: + DISALLOW_DEFAULT_CONSTRUCTOR(SuggestedWord); + + std::vector mCodePoints; + int mScore; + int mType; + int mIndexToPartialCommit; + int mAutoCommitFirstWordConfidence; +}; +} // namespace latinime +#endif /* LATINIME_SUGGESTED_WORD_H */ diff --git a/native/jni/src/suggest/core/result/suggestion_results.cpp b/native/jni/src/suggest/core/result/suggestion_results.cpp new file mode 100644 index 000000000..2be757d83 --- /dev/null +++ b/native/jni/src/suggest/core/result/suggestion_results.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "suggest/core/result/suggestion_results.h" + +namespace latinime { + +void SuggestionResults::outputSuggestions(JNIEnv *env, jintArray outSuggestionCount, + jintArray outputCodePointsArray, jintArray outScoresArray, jintArray outSpaceIndicesArray, + jintArray outTypesArray, jintArray outAutoCommitFirstWordConfidenceArray) { + int outputIndex = 0; + while (!mSuggestedWords.empty()) { + const SuggestedWord &suggestedWord = mSuggestedWords.top(); + suggestedWord.getCodePointCount(); + const int start = outputIndex * MAX_WORD_LENGTH; + env->SetIntArrayRegion(outputCodePointsArray, start, suggestedWord.getCodePointCount(), + suggestedWord.getCodePoint()); + if (suggestedWord.getCodePointCount() < MAX_WORD_LENGTH) { + const int terminal = 0; + env->SetIntArrayRegion(outputCodePointsArray, start + suggestedWord.getCodePointCount(), + 1 /* len */, &terminal); + } + const int score = suggestedWord.getScore(); + env->SetIntArrayRegion(outScoresArray, outputIndex, 1 /* len */, &score); + const int indexToPartialCommit = suggestedWord.getIndexToPartialCommit(); + env->SetIntArrayRegion(outSpaceIndicesArray, outputIndex, 1 /* len */, + &indexToPartialCommit); + const int type = suggestedWord.getType(); + env->SetIntArrayRegion(outTypesArray, outputIndex, 1 /* len */, &type); + if (mSuggestedWords.size() == 1) { + const int autoCommitFirstWordConfidence = + suggestedWord.getAutoCommitFirstWordConfidence(); + env->SetIntArrayRegion(outAutoCommitFirstWordConfidenceArray, 0 /* start */, + 1 /* len */, &autoCommitFirstWordConfidence); + } + ++outputIndex; + mSuggestedWords.pop(); + } + env->SetIntArrayRegion(outSuggestionCount, 0 /* start */, 1 /* len */, &outputIndex); +} + +void SuggestionResults::addPrediction(const int *const codePoints, const int codePointCount, + const int probability) { + if (codePointCount <= 0 || codePointCount > MAX_WORD_LENGTH + || probability == NOT_A_PROBABILITY) { + // Invalid word. + return; + } + // Use probability as a score of the word. + const int score = probability; + if (getSuggestionCount() >= mMaxSuggestionCount) { + const SuggestedWord &mWorstSuggestion = mSuggestedWords.top(); + if (score > mWorstSuggestion.getScore() || (score == mWorstSuggestion.getScore() + && codePointCount < mWorstSuggestion.getCodePointCount())) { + mSuggestedWords.pop(); + } else { + return; + } + } + mSuggestedWords.push(SuggestedWord(codePoints, codePointCount, score, + Dictionary::KIND_PREDICTION, NOT_AN_INDEX, NOT_A_FIRST_WORD_CONFIDENCE)); +} + +} // namespace latinime diff --git a/native/jni/src/suggest/core/result/suggestion_results.h b/native/jni/src/suggest/core/result/suggestion_results.h new file mode 100644 index 000000000..0b841ca19 --- /dev/null +++ b/native/jni/src/suggest/core/result/suggestion_results.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LATINIME_SUGGESTION_RESULTS_H +#define LATINIME_SUGGESTION_RESULTS_H + +#include +#include + +#include "defines.h" +#include "jni.h" +#include "suggest/core/result/suggested_word.h" + +namespace latinime { + +class SuggestionResults { + public: + explicit SuggestionResults(const int maxSuggestionCount) + : mMaxSuggestionCount(maxSuggestionCount), mSuggestedWords() {} + + // Returns suggestion count. + void outputSuggestions(JNIEnv *env, jintArray outSuggestionCount, jintArray outCodePointsArray, + jintArray outScoresArray, jintArray outSpaceIndicesArray, jintArray outTypesArray, + jintArray outAutoCommitFirstWordConfidenceArray); + + void addPrediction(const int *const codePoints, const int codePointCount, const int score); + + int getSuggestionCount() const { + return mSuggestedWords.size(); + } + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(SuggestionResults); + + const int mMaxSuggestionCount; + std::priority_queue< + SuggestedWord, std::vector, SuggestedWord::Comparator> mSuggestedWords; +}; +} // namespace latinime +#endif // LATINIME_SUGGESTION_RESULTS_H