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