diff options
7 files changed, 85 insertions, 79 deletions
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java index f2a6f3b2e..e2feb7c4d 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java @@ -405,10 +405,11 @@ public final class InputLogic { final int keyboardShiftMode, // TODO: remove these arguments final int currentKeyboardScriptId, final LatinIME.UIHandler handler) { - final InputTransaction inputTransaction = new InputTransaction(settingsValues, event, - SystemClock.uptimeMillis(), mSpaceState, + final Event processedEvent = mWordComposer.processEvent(event); + final InputTransaction inputTransaction = new InputTransaction(settingsValues, + processedEvent, SystemClock.uptimeMillis(), mSpaceState, getActualCapsMode(settingsValues, keyboardShiftMode)); - if (event.mKeyCode != Constants.CODE_DELETE + if (processedEvent.mKeyCode != Constants.CODE_DELETE || inputTransaction.mTimestamp > mLastKeyTime + Constants.LONG_PRESS_MILLISECONDS) { mDeleteCount = 0; } @@ -419,14 +420,14 @@ public final class InputLogic { } // TODO: Consolidate the double-space period timer, mLastKeyTime, and the space state. - if (event.mCodePoint != Constants.CODE_SPACE) { + if (processedEvent.mCodePoint != Constants.CODE_SPACE) { cancelDoubleSpacePeriodCountdown(); } boolean didAutoCorrect = false; - if (event.isFunctionalKeyEvent()) { + if (processedEvent.isFunctionalKeyEvent()) { // A special key, like delete, shift, emoji, or the settings key. - switch (event.mKeyCode) { + switch (processedEvent.mKeyCode) { case Constants.CODE_DELETE: handleBackspace(inputTransaction, currentKeyboardScriptId); // Backspace is a functional key, but it affects the contents of the editor. @@ -478,7 +479,8 @@ public final class InputLogic { case Constants.CODE_SHIFT_ENTER: // TODO: remove this object final Event tmpEvent = Event.createSoftwareKeypressEvent(Constants.CODE_ENTER, - event.mKeyCode, event.mX, event.mY, event.isKeyRepeat()); + processedEvent.mKeyCode, processedEvent.mX, processedEvent.mY, + processedEvent.isKeyRepeat()); final InputTransaction tmpTransaction = new InputTransaction( inputTransaction.mSettingsValues, tmpEvent, inputTransaction.mTimestamp, inputTransaction.mSpaceState, @@ -489,11 +491,11 @@ public final class InputLogic { inputTransaction.setDidAffectContents(); break; default: - throw new RuntimeException("Unknown key code : " + event.mKeyCode); + throw new RuntimeException("Unknown key code : " + processedEvent.mKeyCode); } } else { inputTransaction.setDidAffectContents(); - switch (event.mCodePoint) { + switch (processedEvent.mCodePoint) { case Constants.CODE_ENTER: final EditorInfo editorInfo = getCurrentInputEditorInfo(); final int imeOptionsActionId = @@ -522,11 +524,11 @@ public final class InputLogic { break; } } - if (!didAutoCorrect && event.mKeyCode != Constants.CODE_SHIFT - && event.mKeyCode != Constants.CODE_CAPSLOCK - && event.mKeyCode != Constants.CODE_SWITCH_ALPHA_SYMBOL) + if (!didAutoCorrect && processedEvent.mKeyCode != Constants.CODE_SHIFT + && processedEvent.mKeyCode != Constants.CODE_CAPSLOCK + && processedEvent.mKeyCode != Constants.CODE_SWITCH_ALPHA_SYMBOL) mLastComposedWord.deactivate(); - if (Constants.CODE_DELETE != event.mKeyCode) { + if (Constants.CODE_DELETE != processedEvent.mKeyCode) { mEnteredText = null; } mConnection.endBatchEdit(); @@ -712,8 +714,7 @@ public final class InputLogic { */ private void handleNonSeparator(final SettingsValues settingsValues, final InputTransaction inputTransaction) { - final Event processedEvent = mWordComposer.processEvent(inputTransaction.mEvent); - final int codePoint = processedEvent.mCodePoint; + final int codePoint = inputTransaction.mEvent.mCodePoint; // TODO: refactor this method to stop flipping isComposingWord around all the time, and // make it shorter (possibly cut into several pieces). Also factor handleNonSpecialCharacter // which has the same name as other handle* methods but is not the same. @@ -763,7 +764,7 @@ public final class InputLogic { resetComposingState(false /* alsoResetLastComposedWord */); } if (isComposingWord) { - mWordComposer.applyProcessedEvent(processedEvent); + mWordComposer.applyProcessedEvent(inputTransaction.mEvent); // If it's the first letter, make note of auto-caps state if (mWordComposer.isSingleLetter()) { mWordComposer.setCapitalizedModeAtStartComposingTime(inputTransaction.mShiftState); @@ -772,7 +773,7 @@ public final class InputLogic { mWordComposer.getTypedWord()), 1); } else { final boolean swapWeakSpace = tryStripSpaceAndReturnWhetherShouldSwapInstead( - inputTransaction, processedEvent.isSuggestionStripPress()); + inputTransaction); if (swapWeakSpace && trySwapSwapperAndSpace(inputTransaction)) { mSpaceState = SpaceState.WEAK; @@ -823,7 +824,7 @@ public final class InputLogic { } final boolean swapWeakSpace = tryStripSpaceAndReturnWhetherShouldSwapInstead( - inputTransaction, isFromSuggestionStrip); + inputTransaction); final boolean isInsideDoubleQuoteOrAfterDigit = Constants.CODE_DOUBLE_QUOTE == codePoint && mConnection.isInsideDoubleQuoteOrAfterDigit(); @@ -903,7 +904,7 @@ public final class InputLogic { private void handleBackspace(final InputTransaction inputTransaction, // TODO: remove this argument, put it into settingsValues final int currentKeyboardScriptId) { - final Event processedEvent = mWordComposer.processEvent(inputTransaction.mEvent); + final Event event = inputTransaction.mEvent; mSpaceState = SpaceState.NONE; mDeleteCount++; @@ -915,7 +916,7 @@ public final class InputLogic { // Then again, even in the case of a key repeat, if the cursor is at start of text, it // can't go any further back, so we can update right away even if it's a key repeat. final int shiftUpdateKind = - processedEvent.isKeyRepeat() && mConnection.getExpectedSelectionStart() > 0 + event.isKeyRepeat() && mConnection.getExpectedSelectionStart() > 0 ? InputTransaction.SHIFT_UPDATE_LATER : InputTransaction.SHIFT_UPDATE_NOW; inputTransaction.requireShiftUpdate(shiftUpdateKind); @@ -935,7 +936,7 @@ public final class InputLogic { mDictionaryFacilitator.removeWordFromPersonalizedDicts(rejectedSuggestion); } } else { - mWordComposer.applyProcessedEvent(processedEvent); + mWordComposer.applyProcessedEvent(event); } if (mWordComposer.isComposingWord()) { mConnection.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1); @@ -1072,12 +1073,12 @@ public final class InputLogic { /* * Strip a trailing space if necessary and returns whether it's a swap weak space situation. * @param inputTransaction The transaction in progress. - * @param isFromSuggestionStrip Whether this code point is coming from the suggestion strip. * @return whether we should swap the space instead of removing it. */ private boolean tryStripSpaceAndReturnWhetherShouldSwapInstead( - final InputTransaction inputTransaction, final boolean isFromSuggestionStrip) { + final InputTransaction inputTransaction) { final int codePoint = inputTransaction.mEvent.mCodePoint; + final boolean isFromSuggestionStrip = inputTransaction.mEvent.isSuggestionStripPress(); if (Constants.CODE_ENTER == codePoint && SpaceState.SWAP_PUNCTUATION == inputTransaction.mSpaceState) { mConnection.removeTrailingSpace(); diff --git a/native/jni/src/suggest/core/dicnode/dic_node.h b/native/jni/src/suggest/core/dicnode/dic_node.h index 92f39ea25..d1b2c87be 100644 --- a/native/jni/src/suggest/core/dicnode/dic_node.h +++ b/native/jni/src/suggest/core/dicnode/dic_node.h @@ -117,7 +117,7 @@ class DicNode { int newPrevWordsPtNodePos[MAX_PREV_WORD_COUNT_FOR_N_GRAM]; newPrevWordsPtNodePos[0] = dicNode->mDicNodeProperties.getPtNodePos(); for (size_t i = 1; i < NELEMS(newPrevWordsPtNodePos); ++i) { - newPrevWordsPtNodePos[i] = dicNode->getNthPrevWordTerminalPtNodePos(i); + newPrevWordsPtNodePos[i] = dicNode->getPrevWordsTerminalPtNodePos()[i - 1]; } mDicNodeProperties.init(rootPtNodeArrayPos, newPrevWordsPtNodePos); mDicNodeState.initAsRootWithPreviousWord(&dicNode->mDicNodeState, @@ -208,12 +208,9 @@ class DicNode { return mDicNodeProperties.getPtNodePos(); } - // Used to get n-gram probability in DicNodeUtils. n is 1-indexed. - int getNthPrevWordTerminalPtNodePos(const int n) const { - if (n <= 0 || n > MAX_PREV_WORD_COUNT_FOR_N_GRAM) { - return NOT_A_DICT_POS; - } - return mDicNodeProperties.getPrevWordsTerminalPtNodePos()[n - 1]; + // TODO: Use view class to return PtNodePos array. + const int *getPrevWordsTerminalPtNodePos() const { + return mDicNodeProperties.getPrevWordsTerminalPtNodePos(); } // Used in DicNodeUtils 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 4445f4aaf..69ea67418 100644 --- a/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp +++ b/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp @@ -85,17 +85,10 @@ namespace latinime { const DictionaryStructureWithBufferPolicy *const dictionaryStructurePolicy, const DicNode *const dicNode, MultiBigramMap *const multiBigramMap) { const int unigramProbability = dicNode->getProbability(); - const int ptNodePos = dicNode->getPtNodePos(); - const int prevWordTerminalPtNodePos = dicNode->getNthPrevWordTerminalPtNodePos(1 /* n */); - if (NOT_A_DICT_POS == ptNodePos || NOT_A_DICT_POS == prevWordTerminalPtNodePos) { - // Note: Normally wordPos comes from the dictionary and should never equal - // NOT_A_VALID_WORD_POS. - return dictionaryStructurePolicy->getProbability(unigramProbability, - NOT_A_PROBABILITY); - } if (multiBigramMap) { + const int *const prevWordsPtNodePos = dicNode->getPrevWordsTerminalPtNodePos(); return multiBigramMap->getBigramProbability(dictionaryStructurePolicy, - prevWordTerminalPtNodePos, ptNodePos, unigramProbability); + prevWordsPtNodePos, dicNode->getPtNodePos(), unigramProbability); } return dictionaryStructurePolicy->getProbability(unigramProbability, NOT_A_PROBABILITY); diff --git a/native/jni/src/suggest/core/dictionary/multi_bigram_map.cpp b/native/jni/src/suggest/core/dictionary/multi_bigram_map.cpp index 012e4dc9c..91f33a8dd 100644 --- a/native/jni/src/suggest/core/dictionary/multi_bigram_map.cpp +++ b/native/jni/src/suggest/core/dictionary/multi_bigram_map.cpp @@ -35,34 +35,30 @@ const int MultiBigramMap::BigramMap::DEFAULT_HASH_MAP_SIZE_FOR_EACH_BIGRAM_MAP = // Also caches the bigrams if there is space remaining and they have not been cached already. int MultiBigramMap::getBigramProbability( const DictionaryStructureWithBufferPolicy *const structurePolicy, - const int wordPosition, const int nextWordPosition, const int unigramProbability) { + const int *const prevWordsPtNodePos, const int nextWordPosition, + const int unigramProbability) { + if (!prevWordsPtNodePos || prevWordsPtNodePos[0] == NOT_A_DICT_POS) { + return structurePolicy->getProbability(unigramProbability, NOT_A_PROBABILITY); + } std::unordered_map<int, BigramMap>::const_iterator mapPosition = - mBigramMaps.find(wordPosition); + mBigramMaps.find(prevWordsPtNodePos[0]); if (mapPosition != mBigramMaps.end()) { return mapPosition->second.getBigramProbability(structurePolicy, nextWordPosition, unigramProbability); } if (mBigramMaps.size() < MAX_CACHED_PREV_WORDS_IN_BIGRAM_MAP) { - addBigramsForWordPosition(structurePolicy, wordPosition); - return mBigramMaps[wordPosition].getBigramProbability(structurePolicy, + addBigramsForWordPosition(structurePolicy, prevWordsPtNodePos); + return mBigramMaps[prevWordsPtNodePos[0]].getBigramProbability(structurePolicy, nextWordPosition, unigramProbability); } - return readBigramProbabilityFromBinaryDictionary(structurePolicy, wordPosition, + return readBigramProbabilityFromBinaryDictionary(structurePolicy, prevWordsPtNodePos, nextWordPosition, unigramProbability); } void MultiBigramMap::BigramMap::init( - const DictionaryStructureWithBufferPolicy *const structurePolicy, const int nodePos) { - BinaryDictionaryBigramsIterator bigramsIt = - structurePolicy->getBigramsIteratorOfPtNode(nodePos); - while (bigramsIt.hasNext()) { - bigramsIt.next(); - if (bigramsIt.getBigramPos() == NOT_A_DICT_POS) { - continue; - } - mBigramMap[bigramsIt.getBigramPos()] = bigramsIt.getProbability(); - mBloomFilter.setInFilter(bigramsIt.getBigramPos()); - } + const DictionaryStructureWithBufferPolicy *const structurePolicy, + const int *const prevWordsPtNodePos) { + structurePolicy->iterateNgramEntries(prevWordsPtNodePos, this /* listener */); } int MultiBigramMap::BigramMap::getBigramProbability( @@ -79,25 +75,33 @@ int MultiBigramMap::BigramMap::getBigramProbability( return structurePolicy->getProbability(unigramProbability, bigramProbability); } +void MultiBigramMap::BigramMap::onVisitEntry(const int ngramProbability, + const int targetPtNodePos) { + if (targetPtNodePos == NOT_A_DICT_POS) { + return; + } + mBigramMap[targetPtNodePos] = ngramProbability; + mBloomFilter.setInFilter(targetPtNodePos); +} + void MultiBigramMap::addBigramsForWordPosition( - const DictionaryStructureWithBufferPolicy *const structurePolicy, const int position) { - mBigramMaps[position].init(structurePolicy, position); + const DictionaryStructureWithBufferPolicy *const structurePolicy, + const int *const prevWordsPtNodePos) { + if (prevWordsPtNodePos) { + mBigramMaps[prevWordsPtNodePos[0]].init(structurePolicy, prevWordsPtNodePos); + } } int MultiBigramMap::readBigramProbabilityFromBinaryDictionary( - const DictionaryStructureWithBufferPolicy *const structurePolicy, const int nodePos, - const int nextWordPosition, const int unigramProbability) { - int bigramProbability = NOT_A_PROBABILITY; - BinaryDictionaryBigramsIterator bigramsIt = - structurePolicy->getBigramsIteratorOfPtNode(nodePos); - while (bigramsIt.hasNext()) { - bigramsIt.next(); - if (bigramsIt.getBigramPos() == nextWordPosition) { - bigramProbability = bigramsIt.getProbability(); - break; - } + const DictionaryStructureWithBufferPolicy *const structurePolicy, + const int *const prevWordsPtNodePos, const int nextWordPosition, + const int unigramProbability) { + const int bigramProbability = structurePolicy->getProbabilityOfPtNode(prevWordsPtNodePos, + nextWordPosition); + if (bigramProbability != NOT_A_PROBABILITY) { + return bigramProbability; } - return structurePolicy->getProbability(unigramProbability, bigramProbability); + return structurePolicy->getProbability(unigramProbability, NOT_A_PROBABILITY); } } // namespace latinime diff --git a/native/jni/src/suggest/core/dictionary/multi_bigram_map.h b/native/jni/src/suggest/core/dictionary/multi_bigram_map.h index 195b5e22f..ad36dde83 100644 --- a/native/jni/src/suggest/core/dictionary/multi_bigram_map.h +++ b/native/jni/src/suggest/core/dictionary/multi_bigram_map.h @@ -23,6 +23,7 @@ #include "defines.h" #include "suggest/core/dictionary/binary_dictionary_bigrams_iterator.h" #include "suggest/core/dictionary/bloom_filter.h" +#include "suggest/core/dictionary/ngram_listener.h" #include "suggest/core/policy/dictionary_structure_with_buffer_policy.h" namespace latinime { @@ -38,7 +39,8 @@ class MultiBigramMap { // Look up the bigram probability for the given word pair from the cached bigram maps. // Also caches the bigrams if there is space remaining and they have not been cached already. int getBigramProbability(const DictionaryStructureWithBufferPolicy *const structurePolicy, - const int wordPosition, const int nextWordPosition, const int unigramProbability); + const int *const prevWordsPtNodePos, const int nextWordPosition, + const int unigramProbability); void clear() { mBigramMaps.clear(); @@ -47,32 +49,35 @@ class MultiBigramMap { private: DISALLOW_COPY_AND_ASSIGN(MultiBigramMap); - class BigramMap { + class BigramMap : public NgramListener { public: BigramMap() : mBigramMap(DEFAULT_HASH_MAP_SIZE_FOR_EACH_BIGRAM_MAP), mBloomFilter() {} - ~BigramMap() {} + // Copy constructor needed for std::unordered_map. + BigramMap(const BigramMap &bigramMap) + : mBigramMap(bigramMap.mBigramMap), mBloomFilter(bigramMap.mBloomFilter) {} + virtual ~BigramMap() {} void init(const DictionaryStructureWithBufferPolicy *const structurePolicy, - const int nodePos); - + const int *const prevWordsPtNodePos); int getBigramProbability( const DictionaryStructureWithBufferPolicy *const structurePolicy, const int nextWordPosition, const int unigramProbability) const; + virtual void onVisitEntry(const int ngramProbability, const int targetPtNodePos); private: - // NOTE: The BigramMap class doesn't use DISALLOW_COPY_AND_ASSIGN() because its default - // copy constructor is needed for use in hash_map. static const int DEFAULT_HASH_MAP_SIZE_FOR_EACH_BIGRAM_MAP; std::unordered_map<int, int> mBigramMap; BloomFilter mBloomFilter; }; void addBigramsForWordPosition( - const DictionaryStructureWithBufferPolicy *const structurePolicy, const int position); + const DictionaryStructureWithBufferPolicy *const structurePolicy, + const int *const prevWordsPtNodePos); int readBigramProbabilityFromBinaryDictionary( - const DictionaryStructureWithBufferPolicy *const structurePolicy, const int nodePos, - const int nextWordPosition, const int unigramProbability); + const DictionaryStructureWithBufferPolicy *const structurePolicy, + const int *const prevWordsPtNodePos, const int nextWordPosition, + const int unigramProbability); static const size_t MAX_CACHED_PREV_WORDS_IN_BIGRAM_MAP; std::unordered_map<int, BigramMap> mBigramMaps; diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/trie_map.cpp b/native/jni/src/suggest/policyimpl/dictionary/utils/trie_map.cpp index ca79c18e5..2904b1e77 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/utils/trie_map.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/utils/trie_map.cpp @@ -43,6 +43,10 @@ TrieMap::TrieMap() : mBuffer(MAX_BUFFER_SIZE) { writeEntry(EMPTY_BITMAP_ENTRY, ROOT_BITMAP_ENTRY_INDEX); } +TrieMap::TrieMap(uint8_t *const buffer, const int bufferSize) + : mBuffer(buffer, bufferSize, + BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE) {} + void TrieMap::dump(const int from, const int to) const { AKLOGI("BufSize: %d", mBuffer.getTailPosition()); for (int i = from; i < to; ++i) { diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/trie_map.h b/native/jni/src/suggest/policyimpl/dictionary/utils/trie_map.h index db278f5f1..8b33346e6 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/utils/trie_map.h +++ b/native/jni/src/suggest/policyimpl/dictionary/utils/trie_map.h @@ -160,6 +160,8 @@ class TrieMap { static const uint64_t MAX_VALUE; TrieMap(); + // Construct TrieMap using existing data in the memory region written by save(). + TrieMap(uint8_t *const buffer, const int bufferSize); void dump(const int from = 0, const int to = 0) const; bool isNearSizeLimit() const { |