1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef LATINIME_DIC_TRAVERSE_SESSION_H 18 #define LATINIME_DIC_TRAVERSE_SESSION_H 19 20 #include <vector> 21 22 #include "defines.h" 23 #include "dictionary/utils/multi_bigram_map.h" 24 #include "jni.h" 25 #include "suggest/core/dicnode/dic_nodes_cache.h" 26 #include "suggest/core/layout/proximity_info_state.h" 27 #include "utils/int_array_view.h" 28 29 namespace latinime { 30 31 class Dictionary; 32 class DictionaryStructureWithBufferPolicy; 33 class NgramContext; 34 class ProximityInfo; 35 class SuggestOptions; 36 37 class DicTraverseSession { 38 public: 39 40 // A factory method for DicTraverseSession getSessionInstance(JNIEnv * env,jstring localeStr,jlong dictSize)41 static AK_FORCE_INLINE void *getSessionInstance(JNIEnv *env, jstring localeStr, 42 jlong dictSize) { 43 // To deal with the trade-off between accuracy and memory space, large cache is used for 44 // dictionaries larger that the threshold 45 return new DicTraverseSession(env, localeStr, 46 dictSize >= DICTIONARY_SIZE_THRESHOLD_TO_USE_LARGE_CACHE_FOR_SUGGESTION); 47 } 48 releaseSessionInstance(DicTraverseSession * traverseSession)49 static AK_FORCE_INLINE void releaseSessionInstance(DicTraverseSession *traverseSession) { 50 delete traverseSession; 51 } 52 DicTraverseSession(JNIEnv * env,jstring localeStr,bool usesLargeCache)53 AK_FORCE_INLINE DicTraverseSession(JNIEnv *env, jstring localeStr, bool usesLargeCache) 54 : mPrevWordIdCount(0), mProximityInfo(nullptr), mDictionary(nullptr), 55 mSuggestOptions(nullptr), mDicNodesCache(usesLargeCache), mMultiBigramMap(), 56 mInputSize(0), mMaxPointerCount(1), mMultiWordCostMultiplier(1.0f) { 57 // NOTE: mProximityInfoStates is an array of instances. 58 // No need to initialize it explicitly here. 59 } 60 61 // Non virtual inline destructor -- never inherit this class ~DicTraverseSession()62 AK_FORCE_INLINE ~DicTraverseSession() {} 63 64 void init(const Dictionary *dictionary, const NgramContext *const ngramContext, 65 const SuggestOptions *const suggestOptions); 66 // TODO: Remove and merge into init 67 void setupForGetSuggestions(const ProximityInfo *pInfo, const int *inputCodePoints, 68 const int inputSize, const int *const inputXs, const int *const inputYs, 69 const int *const times, const int *const pointerIds, const float maxSpatialDistance, 70 const int maxPointerCount); 71 void resetCache(const int thresholdForNextActiveDicNodes, const int maxWords); 72 73 const DictionaryStructureWithBufferPolicy *getDictionaryStructurePolicy() const; 74 75 //-------------------- 76 // getters and setters 77 //-------------------- getProximityInfo()78 const ProximityInfo *getProximityInfo() const { return mProximityInfo; } getSuggestOptions()79 const SuggestOptions *getSuggestOptions() const { return mSuggestOptions; } getPrevWordIds()80 const WordIdArrayView getPrevWordIds() const { 81 return WordIdArrayView::fromArray(mPrevWordIdArray).limit(mPrevWordIdCount); 82 } getDicTraverseCache()83 DicNodesCache *getDicTraverseCache() { return &mDicNodesCache; } getMultiBigramMap()84 MultiBigramMap *getMultiBigramMap() { return &mMultiBigramMap; } getProximityInfoState(int id)85 const ProximityInfoState *getProximityInfoState(int id) const { 86 return &mProximityInfoStates[id]; 87 } getInputSize()88 int getInputSize() const { return mInputSize; } 89 isOnlyOnePointerUsed(int * pointerId)90 bool isOnlyOnePointerUsed(int *pointerId) const { 91 // Not in the dictionary word 92 int usedPointerCount = 0; 93 int usedPointerId = 0; 94 for (int i = 0; i < mMaxPointerCount; ++i) { 95 if (mProximityInfoStates[i].isUsed()) { 96 ++usedPointerCount; 97 usedPointerId = i; 98 } 99 } 100 if (usedPointerCount != 1) { 101 return false; 102 } 103 if (pointerId) { 104 *pointerId = usedPointerId; 105 } 106 return true; 107 } 108 getProximityTypeG(const DicNode * const dicNode,const int childCodePoint)109 ProximityType getProximityTypeG(const DicNode *const dicNode, const int childCodePoint) const { 110 ProximityType proximityType = UNRELATED_CHAR; 111 for (int i = 0; i < MAX_POINTER_COUNT_G; ++i) { 112 if (!mProximityInfoStates[i].isUsed()) { 113 continue; 114 } 115 const int pointerId = dicNode->getInputIndex(i); 116 proximityType = mProximityInfoStates[i].getProximityTypeG(pointerId, childCodePoint); 117 ASSERT(proximityType == UNRELATED_CHAR || proximityType == MATCH_CHAR); 118 // TODO: Make this more generic 119 // Currently we assume there are only two types here -- UNRELATED_CHAR 120 // and MATCH_CHAR 121 if (proximityType != UNRELATED_CHAR) { 122 return proximityType; 123 } 124 } 125 return proximityType; 126 } 127 isCacheBorderForTyping(const int inputSize)128 AK_FORCE_INLINE bool isCacheBorderForTyping(const int inputSize) const { 129 return mDicNodesCache.isCacheBorderForTyping(inputSize); 130 } 131 132 /** 133 * Returns whether or not it is possible to continue suggestion from the previous search. 134 */ 135 // TODO: Remove. No need to check once the session is fully implemented. isContinuousSuggestionPossible()136 bool isContinuousSuggestionPossible() const { 137 if (!mDicNodesCache.hasCachedDicNodesForContinuousSuggestion()) { 138 return false; 139 } 140 ASSERT(mMaxPointerCount <= MAX_POINTER_COUNT_G); 141 for (int i = 0; i < mMaxPointerCount; ++i) { 142 const ProximityInfoState *const pInfoState = getProximityInfoState(i); 143 // If a proximity info state is not continuous suggestion possible, 144 // do not continue searching. 145 if (pInfoState->isUsed() && !pInfoState->isContinuousSuggestionPossible()) { 146 return false; 147 } 148 } 149 return true; 150 } 151 isTouchPositionCorrectionEnabled()152 bool isTouchPositionCorrectionEnabled() const { 153 return mProximityInfoStates[0].touchPositionCorrectionEnabled(); 154 } 155 getMultiWordCostMultiplier()156 float getMultiWordCostMultiplier() const { 157 return mMultiWordCostMultiplier; 158 } 159 160 private: 161 DISALLOW_IMPLICIT_CONSTRUCTORS(DicTraverseSession); 162 // threshold to start caching 163 static const int CACHE_START_INPUT_LENGTH_THRESHOLD; 164 static const int DICTIONARY_SIZE_THRESHOLD_TO_USE_LARGE_CACHE_FOR_SUGGESTION; 165 void initializeProximityInfoStates(const int *const inputCodePoints, const int *const inputXs, 166 const int *const inputYs, const int *const times, const int *const pointerIds, 167 const int inputSize, const float maxSpatialDistance, const int maxPointerCount); 168 169 WordIdArray<MAX_PREV_WORD_COUNT_FOR_N_GRAM> mPrevWordIdArray; 170 size_t mPrevWordIdCount; 171 const ProximityInfo *mProximityInfo; 172 const Dictionary *mDictionary; 173 const SuggestOptions *mSuggestOptions; 174 175 DicNodesCache mDicNodesCache; 176 // Temporary cache for bigram frequencies 177 MultiBigramMap mMultiBigramMap; 178 ProximityInfoState mProximityInfoStates[MAX_POINTER_COUNT_G]; 179 180 int mInputSize; 181 int mMaxPointerCount; 182 183 ///////////////////////////////// 184 // Configuration per dictionary 185 float mMultiWordCostMultiplier; 186 187 }; 188 } // namespace latinime 189 #endif // LATINIME_DIC_TRAVERSE_SESSION_H 190