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_NODES_CACHE_H 18 #define LATINIME_DIC_NODES_CACHE_H 19 20 #include <stdint.h> 21 22 #include "defines.h" 23 #include "suggest/core/dicnode/dic_node_priority_queue.h" 24 25 namespace latinime { 26 27 class DicNode; 28 29 /** 30 * Class for controlling dicNode search priority queue and lexicon trie traversal. 31 */ 32 class DicNodesCache { 33 public: 34 AK_FORCE_INLINE explicit DicNodesCache(const bool usesLargeCapacityCache) 35 : mUsesLargeCapacityCache(usesLargeCapacityCache), 36 mDicNodePriorityQueue0(getCacheCapacity()), 37 mDicNodePriorityQueue1(getCacheCapacity()), 38 mDicNodePriorityQueue2(getCacheCapacity()), 39 mDicNodePriorityQueueForTerminal(MAX_RESULTS), 40 mActiveDicNodes(&mDicNodePriorityQueue0), 41 mNextActiveDicNodes(&mDicNodePriorityQueue1), 42 mCachedDicNodesForContinuousSuggestion(&mDicNodePriorityQueue2), 43 mTerminalDicNodes(&mDicNodePriorityQueueForTerminal), 44 mInputIndex(0), mLastCachedInputIndex(0) {} 45 46 AK_FORCE_INLINE virtual ~DicNodesCache() {} 47 48 AK_FORCE_INLINE void reset(const int nextActiveSize, const int terminalSize) { 49 mInputIndex = 0; 50 mLastCachedInputIndex = 0; 51 // We want to use the max capacity for the current active dic node queue. 52 mActiveDicNodes->clearAndResizeToCapacity(); 53 // nextActiveSize is used to limit the next iteration's active dic node size. 54 const int nextActiveSizeFittingToTheCapacity = min(nextActiveSize, getCacheCapacity()); 55 mNextActiveDicNodes->clearAndResize(nextActiveSizeFittingToTheCapacity); 56 mTerminalDicNodes->clearAndResize(terminalSize); 57 // We want to use the max capacity for the cached dic nodes that will be used for the 58 // continuous suggestion. 59 mCachedDicNodesForContinuousSuggestion->clearAndResizeToCapacity(); 60 } 61 62 AK_FORCE_INLINE void continueSearch() { 63 resetTemporaryCaches(); 64 restoreActiveDicNodesFromCache(); 65 } 66 67 AK_FORCE_INLINE void advanceActiveDicNodes() { 68 if (DEBUG_DICT) { 69 AKLOGI("Advance active %d nodes.", mNextActiveDicNodes->getSize()); 70 } 71 if (DEBUG_DICT_FULL) { 72 mNextActiveDicNodes->dump(); 73 } 74 mNextActiveDicNodes = 75 moveNodesAndReturnReusableEmptyQueue(mNextActiveDicNodes, &mActiveDicNodes); 76 } 77 78 DicNode *setCommitPoint(int commitPoint); 79 80 int activeSize() const { return mActiveDicNodes->getSize(); } 81 int terminalSize() const { return mTerminalDicNodes->getSize(); } 82 bool isLookAheadCorrectionInputIndex(const int inputIndex) const { 83 return inputIndex == mInputIndex - 1; 84 } 85 void advanceInputIndex(const int inputSize) { 86 if (mInputIndex < inputSize) { 87 mInputIndex++; 88 } 89 } 90 91 AK_FORCE_INLINE void copyPushTerminal(DicNode *dicNode) { 92 mTerminalDicNodes->copyPush(dicNode); 93 } 94 95 AK_FORCE_INLINE void copyPushActive(DicNode *dicNode) { 96 mActiveDicNodes->copyPush(dicNode); 97 } 98 99 AK_FORCE_INLINE bool copyPushContinue(DicNode *dicNode) { 100 return mCachedDicNodesForContinuousSuggestion->copyPush(dicNode); 101 } 102 103 AK_FORCE_INLINE void copyPushNextActive(DicNode *dicNode) { 104 DicNode *pushedDicNode = mNextActiveDicNodes->copyPush(dicNode); 105 if (!pushedDicNode) { 106 if (dicNode->isCached()) { 107 dicNode->remove(); 108 } 109 // We simply drop any dic node that was not cached, ignoring the slim chance 110 // that one of its children represents what the user really wanted. 111 } 112 } 113 114 void popTerminal(DicNode *dest) { 115 mTerminalDicNodes->copyPop(dest); 116 } 117 118 void popActive(DicNode *dest) { 119 mActiveDicNodes->copyPop(dest); 120 } 121 122 bool hasCachedDicNodesForContinuousSuggestion() const { 123 return mCachedDicNodesForContinuousSuggestion 124 && mCachedDicNodesForContinuousSuggestion->getSize() > 0; 125 } 126 127 AK_FORCE_INLINE bool isCacheBorderForTyping(const int inputSize) const { 128 // TODO: Move this variable to header 129 static const int CACHE_BACK_LENGTH = 3; 130 const int cacheInputIndex = inputSize - CACHE_BACK_LENGTH; 131 const bool shouldCache = (cacheInputIndex == mInputIndex) 132 && (cacheInputIndex != mLastCachedInputIndex); 133 return shouldCache; 134 } 135 136 AK_FORCE_INLINE void updateLastCachedInputIndex() { 137 mLastCachedInputIndex = mInputIndex; 138 } 139 140 private: 141 DISALLOW_COPY_AND_ASSIGN(DicNodesCache); 142 143 AK_FORCE_INLINE void restoreActiveDicNodesFromCache() { 144 if (DEBUG_DICT) { 145 AKLOGI("Restore %d nodes. inputIndex = %d.", 146 mCachedDicNodesForContinuousSuggestion->getSize(), mLastCachedInputIndex); 147 } 148 if (DEBUG_DICT_FULL || DEBUG_CACHE) { 149 mCachedDicNodesForContinuousSuggestion->dump(); 150 } 151 mInputIndex = mLastCachedInputIndex; 152 mCachedDicNodesForContinuousSuggestion = moveNodesAndReturnReusableEmptyQueue( 153 mCachedDicNodesForContinuousSuggestion, &mActiveDicNodes); 154 } 155 156 AK_FORCE_INLINE static DicNodePriorityQueue *moveNodesAndReturnReusableEmptyQueue( 157 DicNodePriorityQueue *src, DicNodePriorityQueue **dest) { 158 const int srcMaxSize = src->getMaxSize(); 159 const int destMaxSize = (*dest)->getMaxSize(); 160 DicNodePriorityQueue *tmp = *dest; 161 *dest = src; 162 (*dest)->setMaxSize(destMaxSize); 163 tmp->clearAndResize(srcMaxSize); 164 return tmp; 165 } 166 167 AK_FORCE_INLINE int getCacheCapacity() const { 168 return mUsesLargeCapacityCache ? 169 LARGE_PRIORITY_QUEUE_CAPACITY : SMALL_PRIORITY_QUEUE_CAPACITY; 170 } 171 172 AK_FORCE_INLINE void resetTemporaryCaches() { 173 mActiveDicNodes->clear(); 174 mNextActiveDicNodes->clear(); 175 mTerminalDicNodes->clear(); 176 } 177 178 static const int LARGE_PRIORITY_QUEUE_CAPACITY; 179 static const int SMALL_PRIORITY_QUEUE_CAPACITY; 180 181 const bool mUsesLargeCapacityCache; 182 // Instances 183 DicNodePriorityQueue mDicNodePriorityQueue0; 184 DicNodePriorityQueue mDicNodePriorityQueue1; 185 DicNodePriorityQueue mDicNodePriorityQueue2; 186 DicNodePriorityQueue mDicNodePriorityQueueForTerminal; 187 188 // Active dicNodes currently being expanded. 189 DicNodePriorityQueue *mActiveDicNodes; 190 // Next dicNodes to be expanded. 191 DicNodePriorityQueue *mNextActiveDicNodes; 192 // Cached dicNodes used for continuous suggestion. 193 DicNodePriorityQueue *mCachedDicNodesForContinuousSuggestion; 194 // Current top terminal dicNodes. 195 DicNodePriorityQueue *mTerminalDicNodes; 196 int mInputIndex; 197 int mLastCachedInputIndex; 198 }; 199 } // namespace latinime 200 #endif // LATINIME_DIC_NODES_CACHE_H 201