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 <stdint.h> 21 #include <vector> 22 23 #include "defines.h" 24 #include "jni.h" 25 #include "suggest/core/dicnode/dic_nodes_cache.h" 26 #include "suggest/core/dictionary/multi_bigram_map.h" 27 #include "suggest/core/layout/proximity_info_state.h" 28 29 namespace latinime { 30 31 class Dictionary; 32 class DictionaryStructureWithBufferPolicy; 33 class ProximityInfo; 34 class SuggestOptions; 35 36 class DicTraverseSession { 37 public: 38 39 // A factory method for DicTraverseSession 40 static AK_FORCE_INLINE void *getSessionInstance(JNIEnv *env, jstring localeStr, 41 jlong dictSize) { 42 // To deal with the trade-off between accuracy and memory space, large cache is used for 43 // dictionaries larger that the threshold 44 return new DicTraverseSession(env, localeStr, 45 dictSize >= DICTIONARY_SIZE_THRESHOLD_TO_USE_LARGE_CACHE_FOR_SUGGESTION); 46 } 47 48 static AK_FORCE_INLINE void initSessionInstance(DicTraverseSession *traverseSession, 49 const Dictionary *const dictionary, const int *prevWord, const int prevWordLength, 50 const SuggestOptions *const suggestOptions) { 51 if (traverseSession) { 52 DicTraverseSession *tSession = static_cast<DicTraverseSession *>(traverseSession); 53 tSession->init(dictionary, prevWord, prevWordLength, suggestOptions); 54 } 55 } 56 57 static AK_FORCE_INLINE void releaseSessionInstance(DicTraverseSession *traverseSession) { 58 delete traverseSession; 59 } 60 61 AK_FORCE_INLINE DicTraverseSession(JNIEnv *env, jstring localeStr, bool usesLargeCache) 62 : mPrevWordPos(NOT_A_DICT_POS), mProximityInfo(0), 63 mDictionary(0), mSuggestOptions(0), mDicNodesCache(usesLargeCache), 64 mMultiBigramMap(), mInputSize(0), mPartiallyCommited(false), mMaxPointerCount(1), 65 mMultiWordCostMultiplier(1.0f) { 66 // NOTE: mProximityInfoStates is an array of instances. 67 // No need to initialize it explicitly here. 68 } 69 70 // Non virtual inline destructor -- never inherit this class 71 AK_FORCE_INLINE ~DicTraverseSession() {} 72 73 void init(const Dictionary *dictionary, const int *prevWord, int prevWordLength, 74 const SuggestOptions *const suggestOptions); 75 // TODO: Remove and merge into init 76 void setupForGetSuggestions(const ProximityInfo *pInfo, const int *inputCodePoints, 77 const int inputSize, const int *const inputXs, const int *const inputYs, 78 const int *const times, const int *const pointerIds, const float maxSpatialDistance, 79 const int maxPointerCount); 80 void resetCache(const int thresholdForNextActiveDicNodes, const int maxWords); 81 82 const DictionaryStructureWithBufferPolicy *getDictionaryStructurePolicy() const; 83 84 //-------------------- 85 // getters and setters 86 //-------------------- 87 const ProximityInfo *getProximityInfo() const { return mProximityInfo; } 88 const SuggestOptions *getSuggestOptions() const { return mSuggestOptions; } 89 int getPrevWordPos() const { return mPrevWordPos; } 90 // TODO: REMOVE 91 void setPrevWordPos(int pos) { mPrevWordPos = pos; } 92 // TODO: Use proper parameter when changed 93 int getDicRootPos() const { return 0; } 94 DicNodesCache *getDicTraverseCache() { return &mDicNodesCache; } 95 MultiBigramMap *getMultiBigramMap() { return &mMultiBigramMap; } 96 const ProximityInfoState *getProximityInfoState(int id) const { 97 return &mProximityInfoStates[id]; 98 } 99 int getInputSize() const { return mInputSize; } 100 void setPartiallyCommited() { mPartiallyCommited = true; } 101 bool isPartiallyCommited() const { return mPartiallyCommited; } 102 103 bool isOnlyOnePointerUsed(int *pointerId) const { 104 // Not in the dictionary word 105 int usedPointerCount = 0; 106 int usedPointerId = 0; 107 for (int i = 0; i < mMaxPointerCount; ++i) { 108 if (mProximityInfoStates[i].isUsed()) { 109 ++usedPointerCount; 110 usedPointerId = i; 111 } 112 } 113 if (usedPointerCount != 1) { 114 return false; 115 } 116 if (pointerId) { 117 *pointerId = usedPointerId; 118 } 119 return true; 120 } 121 122 void getSearchKeys(const DicNode *node, std::vector<int> *const outputSearchKeyVector) const { 123 for (int i = 0; i < MAX_POINTER_COUNT_G; ++i) { 124 if (!mProximityInfoStates[i].isUsed()) { 125 continue; 126 } 127 const int pointerId = node->getInputIndex(i); 128 const std::vector<int> *const searchKeyVector = 129 mProximityInfoStates[i].getSearchKeyVector(pointerId); 130 outputSearchKeyVector->insert(outputSearchKeyVector->end(), searchKeyVector->begin(), 131 searchKeyVector->end()); 132 } 133 } 134 135 ProximityType getProximityTypeG(const DicNode *const node, const int childCodePoint) const { 136 ProximityType proximityType = UNRELATED_CHAR; 137 for (int i = 0; i < MAX_POINTER_COUNT_G; ++i) { 138 if (!mProximityInfoStates[i].isUsed()) { 139 continue; 140 } 141 const int pointerId = node->getInputIndex(i); 142 proximityType = mProximityInfoStates[i].getProximityTypeG(pointerId, childCodePoint); 143 ASSERT(proximityType == UNRELATED_CHAR || proximityType == MATCH_CHAR); 144 // TODO: Make this more generic 145 // Currently we assume there are only two types here -- UNRELATED_CHAR 146 // and MATCH_CHAR 147 if (proximityType != UNRELATED_CHAR) { 148 return proximityType; 149 } 150 } 151 return proximityType; 152 } 153 154 AK_FORCE_INLINE bool isCacheBorderForTyping(const int inputSize) const { 155 return mDicNodesCache.isCacheBorderForTyping(inputSize); 156 } 157 158 /** 159 * Returns whether or not it is possible to continue suggestion from the previous search. 160 */ 161 // TODO: Remove. No need to check once the session is fully implemented. 162 bool isContinuousSuggestionPossible() const { 163 if (!mDicNodesCache.hasCachedDicNodesForContinuousSuggestion()) { 164 return false; 165 } 166 ASSERT(mMaxPointerCount <= MAX_POINTER_COUNT_G); 167 for (int i = 0; i < mMaxPointerCount; ++i) { 168 const ProximityInfoState *const pInfoState = getProximityInfoState(i); 169 // If a proximity info state is not continuous suggestion possible, 170 // do not continue searching. 171 if (pInfoState->isUsed() && !pInfoState->isContinuousSuggestionPossible()) { 172 return false; 173 } 174 } 175 return true; 176 } 177 178 bool isTouchPositionCorrectionEnabled() const { 179 return mProximityInfoStates[0].touchPositionCorrectionEnabled(); 180 } 181 182 float getMultiWordCostMultiplier() const { 183 return mMultiWordCostMultiplier; 184 } 185 186 private: 187 DISALLOW_IMPLICIT_CONSTRUCTORS(DicTraverseSession); 188 // threshold to start caching 189 static const int CACHE_START_INPUT_LENGTH_THRESHOLD; 190 static const int DICTIONARY_SIZE_THRESHOLD_TO_USE_LARGE_CACHE_FOR_SUGGESTION; 191 void initializeProximityInfoStates(const int *const inputCodePoints, const int *const inputXs, 192 const int *const inputYs, const int *const times, const int *const pointerIds, 193 const int inputSize, const float maxSpatialDistance, const int maxPointerCount); 194 195 int mPrevWordPos; 196 const ProximityInfo *mProximityInfo; 197 const Dictionary *mDictionary; 198 const SuggestOptions *mSuggestOptions; 199 200 DicNodesCache mDicNodesCache; 201 // Temporary cache for bigram frequencies 202 MultiBigramMap mMultiBigramMap; 203 ProximityInfoState mProximityInfoStates[MAX_POINTER_COUNT_G]; 204 205 int mInputSize; 206 bool mPartiallyCommited; 207 int mMaxPointerCount; 208 209 ///////////////////////////////// 210 // Configuration per dictionary 211 float mMultiWordCostMultiplier; 212 213 }; 214 } // namespace latinime 215 #endif // LATINIME_DIC_TRAVERSE_SESSION_H 216