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