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 <algorithm> 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: DicNodesCache(const bool usesLargeCapacityCache)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 ~DicNodesCache()46 AK_FORCE_INLINE virtual ~DicNodesCache() {} 47 reset(const int nextActiveSize,const int terminalSize)48 AK_FORCE_INLINE void reset(const int nextActiveSize, const int terminalSize) { 49 mInputIndex = 0; 50 mLastCachedInputIndex = 0; 51 // The size of current active DicNode queue doesn't have to be changed. 52 mActiveDicNodes->clear(); 53 // nextActiveSize is used to limit the next iteration's active DicNode size. 54 const int nextActiveSizeFittingToTheCapacity = std::min(nextActiveSize, getCacheCapacity()); 55 mNextActiveDicNodes->clearAndResize(nextActiveSizeFittingToTheCapacity); 56 mTerminalDicNodes->clearAndResize(terminalSize); 57 // The size of cached DicNode queue doesn't have to be changed. 58 mCachedDicNodesForContinuousSuggestion->clear(); 59 } 60 continueSearch()61 AK_FORCE_INLINE void continueSearch() { 62 resetTemporaryCaches(); 63 restoreActiveDicNodesFromCache(); 64 } 65 advanceActiveDicNodes()66 AK_FORCE_INLINE void advanceActiveDicNodes() { 67 if (DEBUG_DICT) { 68 AKLOGI("Advance active %d nodes.", mNextActiveDicNodes->getSize()); 69 } 70 if (DEBUG_DICT_FULL) { 71 mNextActiveDicNodes->dump(); 72 } 73 mNextActiveDicNodes = 74 moveNodesAndReturnReusableEmptyQueue(mNextActiveDicNodes, &mActiveDicNodes); 75 } 76 activeSize()77 int activeSize() const { return mActiveDicNodes->getSize(); } terminalSize()78 int terminalSize() const { return mTerminalDicNodes->getSize(); } isLookAheadCorrectionInputIndex(const int inputIndex)79 bool isLookAheadCorrectionInputIndex(const int inputIndex) const { 80 return inputIndex == mInputIndex - 1; 81 } advanceInputIndex(const int inputSize)82 void advanceInputIndex(const int inputSize) { 83 if (mInputIndex < inputSize) { 84 mInputIndex++; 85 } 86 } 87 copyPushTerminal(DicNode * dicNode)88 AK_FORCE_INLINE void copyPushTerminal(DicNode *dicNode) { 89 mTerminalDicNodes->copyPush(dicNode); 90 } 91 copyPushActive(DicNode * dicNode)92 AK_FORCE_INLINE void copyPushActive(DicNode *dicNode) { 93 mActiveDicNodes->copyPush(dicNode); 94 } 95 copyPushContinue(DicNode * dicNode)96 AK_FORCE_INLINE void copyPushContinue(DicNode *dicNode) { 97 mCachedDicNodesForContinuousSuggestion->copyPush(dicNode); 98 } 99 copyPushNextActive(DicNode * dicNode)100 AK_FORCE_INLINE void copyPushNextActive(DicNode *dicNode) { 101 mNextActiveDicNodes->copyPush(dicNode); 102 } 103 popTerminal(DicNode * dest)104 void popTerminal(DicNode *dest) { 105 mTerminalDicNodes->copyPop(dest); 106 } 107 popActive(DicNode * dest)108 void popActive(DicNode *dest) { 109 mActiveDicNodes->copyPop(dest); 110 } 111 hasCachedDicNodesForContinuousSuggestion()112 bool hasCachedDicNodesForContinuousSuggestion() const { 113 return mCachedDicNodesForContinuousSuggestion 114 && mCachedDicNodesForContinuousSuggestion->getSize() > 0; 115 } 116 isCacheBorderForTyping(const int inputSize)117 AK_FORCE_INLINE bool isCacheBorderForTyping(const int inputSize) const { 118 // TODO: Move this variable to header 119 static const int CACHE_BACK_LENGTH = 3; 120 const int cacheInputIndex = inputSize - CACHE_BACK_LENGTH; 121 const bool shouldCache = (cacheInputIndex == mInputIndex) 122 && (cacheInputIndex != mLastCachedInputIndex); 123 return shouldCache; 124 } 125 updateLastCachedInputIndex()126 AK_FORCE_INLINE void updateLastCachedInputIndex() { 127 mLastCachedInputIndex = mInputIndex; 128 } 129 130 private: 131 DISALLOW_COPY_AND_ASSIGN(DicNodesCache); 132 restoreActiveDicNodesFromCache()133 AK_FORCE_INLINE void restoreActiveDicNodesFromCache() { 134 if (DEBUG_DICT) { 135 AKLOGI("Restore %d nodes. inputIndex = %d.", 136 mCachedDicNodesForContinuousSuggestion->getSize(), mLastCachedInputIndex); 137 } 138 if (DEBUG_DICT_FULL || DEBUG_CACHE) { 139 mCachedDicNodesForContinuousSuggestion->dump(); 140 } 141 mInputIndex = mLastCachedInputIndex; 142 mCachedDicNodesForContinuousSuggestion = moveNodesAndReturnReusableEmptyQueue( 143 mCachedDicNodesForContinuousSuggestion, &mActiveDicNodes); 144 } 145 moveNodesAndReturnReusableEmptyQueue(DicNodePriorityQueue * src,DicNodePriorityQueue ** dest)146 AK_FORCE_INLINE static DicNodePriorityQueue *moveNodesAndReturnReusableEmptyQueue( 147 DicNodePriorityQueue *src, DicNodePriorityQueue **dest) { 148 const int srcMaxSize = src->getMaxSize(); 149 const int destMaxSize = (*dest)->getMaxSize(); 150 DicNodePriorityQueue *tmp = *dest; 151 *dest = src; 152 (*dest)->setMaxSize(destMaxSize); 153 tmp->clearAndResize(srcMaxSize); 154 return tmp; 155 } 156 getCacheCapacity()157 AK_FORCE_INLINE int getCacheCapacity() const { 158 return mUsesLargeCapacityCache ? 159 LARGE_PRIORITY_QUEUE_CAPACITY : SMALL_PRIORITY_QUEUE_CAPACITY; 160 } 161 resetTemporaryCaches()162 AK_FORCE_INLINE void resetTemporaryCaches() { 163 mActiveDicNodes->clear(); 164 mNextActiveDicNodes->clear(); 165 mTerminalDicNodes->clear(); 166 } 167 168 static const int LARGE_PRIORITY_QUEUE_CAPACITY; 169 static const int SMALL_PRIORITY_QUEUE_CAPACITY; 170 171 const bool mUsesLargeCapacityCache; 172 // Instances 173 DicNodePriorityQueue mDicNodePriorityQueue0; 174 DicNodePriorityQueue mDicNodePriorityQueue1; 175 DicNodePriorityQueue mDicNodePriorityQueue2; 176 DicNodePriorityQueue mDicNodePriorityQueueForTerminal; 177 178 // Active dicNodes currently being expanded. 179 DicNodePriorityQueue *mActiveDicNodes; 180 // Next dicNodes to be expanded. 181 DicNodePriorityQueue *mNextActiveDicNodes; 182 // Cached dicNodes used for continuous suggestion. 183 DicNodePriorityQueue *mCachedDicNodesForContinuousSuggestion; 184 // Current top terminal dicNodes. 185 DicNodePriorityQueue *mTerminalDicNodes; 186 int mInputIndex; 187 int mLastCachedInputIndex; 188 }; 189 } // namespace latinime 190 #endif // LATINIME_DIC_NODES_CACHE_H 191