Home | History | Annotate | Download | only in dictionary
      1 /*
      2  * Copyright (C) 2013, 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_DYNAMIC_PATRICIA_TRIE_READING_HELPER_H
     18 #define LATINIME_DYNAMIC_PATRICIA_TRIE_READING_HELPER_H
     19 
     20 #include <cstddef>
     21 #include <vector>
     22 
     23 #include "defines.h"
     24 #include "suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.h"
     25 #include "suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.h"
     26 #include "suggest/policyimpl/dictionary/patricia_trie_reading_utils.h"
     27 
     28 namespace latinime {
     29 
     30 class BufferWithExtendableBuffer;
     31 class DictionaryBigramsStructurePolicy;
     32 class DictionaryShortcutsStructurePolicy;
     33 
     34 /*
     35  * This class is used for traversing dynamic patricia trie. This class supports iterating nodes and
     36  * dealing with additional buffer. This class counts nodes and node arrays to avoid infinite loop.
     37  */
     38 class DynamicPatriciaTrieReadingHelper {
     39  public:
     40     class TraversingEventListener {
     41      public:
     42         virtual ~TraversingEventListener() {};
     43 
     44         // Returns whether the event handling was succeeded or not.
     45         virtual bool onAscend() = 0;
     46 
     47         // Returns whether the event handling was succeeded or not.
     48         virtual bool onDescend(const int ptNodeArrayPos) = 0;
     49 
     50         // Returns whether the event handling was succeeded or not.
     51         virtual bool onReadingPtNodeArrayTail() = 0;
     52 
     53         // Returns whether the event handling was succeeded or not.
     54         virtual bool onVisitingPtNode(const DynamicPatriciaTrieNodeReader *const node,
     55                 const int *const nodeCodePoints) = 0;
     56 
     57      protected:
     58         TraversingEventListener() {};
     59 
     60      private:
     61         DISALLOW_COPY_AND_ASSIGN(TraversingEventListener);
     62     };
     63 
     64     DynamicPatriciaTrieReadingHelper(const BufferWithExtendableBuffer *const buffer,
     65             const DictionaryBigramsStructurePolicy *const bigramsPolicy,
     66             const DictionaryShortcutsStructurePolicy *const shortcutsPolicy)
     67             : mIsError(false), mReadingState(), mBuffer(buffer),
     68               mNodeReader(mBuffer, bigramsPolicy, shortcutsPolicy), mReadingStateStack() {}
     69 
     70     ~DynamicPatriciaTrieReadingHelper() {}
     71 
     72     AK_FORCE_INLINE bool isError() const {
     73         return mIsError;
     74     }
     75 
     76     AK_FORCE_INLINE bool isEnd() const {
     77         return mReadingState.mPos == NOT_A_DICT_POS;
     78     }
     79 
     80     // Initialize reading state with the head position of a PtNode array.
     81     AK_FORCE_INLINE void initWithPtNodeArrayPos(const int ptNodeArrayPos) {
     82         if (ptNodeArrayPos == NOT_A_DICT_POS) {
     83             mReadingState.mPos = NOT_A_DICT_POS;
     84         } else {
     85             mIsError = false;
     86             mReadingState.mPos = ptNodeArrayPos;
     87             mReadingState.mPrevTotalCodePointCount = 0;
     88             mReadingState.mTotalNodeCount = 0;
     89             mReadingState.mNodeArrayCount = 0;
     90             mReadingState.mPosOfLastForwardLinkField = NOT_A_DICT_POS;
     91             mReadingStateStack.clear();
     92             nextPtNodeArray();
     93             if (!isEnd()) {
     94                 fetchPtNodeInfo();
     95             }
     96         }
     97     }
     98 
     99     // Initialize reading state with the head position of a node.
    100     AK_FORCE_INLINE void initWithPtNodePos(const int ptNodePos) {
    101         if (ptNodePos == NOT_A_DICT_POS) {
    102             mReadingState.mPos = NOT_A_DICT_POS;
    103         } else {
    104             mIsError = false;
    105             mReadingState.mPos = ptNodePos;
    106             mReadingState.mNodeCount = 1;
    107             mReadingState.mPrevTotalCodePointCount = 0;
    108             mReadingState.mTotalNodeCount = 1;
    109             mReadingState.mNodeArrayCount = 1;
    110             mReadingState.mPosOfLastForwardLinkField = NOT_A_DICT_POS;
    111             mReadingState.mPosOfLastPtNodeArrayHead = NOT_A_DICT_POS;
    112             mReadingStateStack.clear();
    113             fetchPtNodeInfo();
    114         }
    115     }
    116 
    117     AK_FORCE_INLINE const DynamicPatriciaTrieNodeReader* getNodeReader() const {
    118         return &mNodeReader;
    119     }
    120 
    121     AK_FORCE_INLINE bool isValidTerminalNode() const {
    122         return !isEnd() && !mNodeReader.isDeleted() && mNodeReader.isTerminal();
    123     }
    124 
    125     AK_FORCE_INLINE bool isMatchedCodePoint(const int index, const int codePoint) const {
    126         return mMergedNodeCodePoints[index] == codePoint;
    127     }
    128 
    129     // Return code point count exclude the last read node's code points.
    130     AK_FORCE_INLINE int getPrevTotalCodePointCount() const {
    131         return mReadingState.mPrevTotalCodePointCount;
    132     }
    133 
    134     // Return code point count include the last read node's code points.
    135     AK_FORCE_INLINE int getTotalCodePointCount() const {
    136         return mReadingState.mPrevTotalCodePointCount + mNodeReader.getCodePointCount();
    137     }
    138 
    139     AK_FORCE_INLINE void fetchMergedNodeCodePointsInReverseOrder(
    140             const int index, int *const outCodePoints) const {
    141         const int nodeCodePointCount = mNodeReader.getCodePointCount();
    142         for (int i =  0; i < nodeCodePointCount; ++i) {
    143             outCodePoints[index + i] = mMergedNodeCodePoints[nodeCodePointCount - 1 - i];
    144         }
    145     }
    146 
    147     AK_FORCE_INLINE const int *getMergedNodeCodePoints() const {
    148         return mMergedNodeCodePoints;
    149     }
    150 
    151     AK_FORCE_INLINE void readNextSiblingNode() {
    152         mReadingState.mNodeCount -= 1;
    153         mReadingState.mPos = mNodeReader.getSiblingNodePos();
    154         if (mReadingState.mNodeCount <= 0) {
    155             // All nodes in the current node array have been read.
    156             followForwardLink();
    157             if (!isEnd()) {
    158                 fetchPtNodeInfo();
    159             }
    160         } else {
    161             fetchPtNodeInfo();
    162         }
    163     }
    164 
    165     // Read the first child node of the current node.
    166     AK_FORCE_INLINE void readChildNode() {
    167         if (mNodeReader.hasChildren()) {
    168             mReadingState.mPrevTotalCodePointCount += mNodeReader.getCodePointCount();
    169             mReadingState.mTotalNodeCount = 0;
    170             mReadingState.mNodeArrayCount = 0;
    171             mReadingState.mPos = mNodeReader.getChildrenPos();
    172             mReadingState.mPosOfLastForwardLinkField = NOT_A_DICT_POS;
    173             // Read children node array.
    174             nextPtNodeArray();
    175             if (!isEnd()) {
    176                 fetchPtNodeInfo();
    177             }
    178         } else {
    179             mReadingState.mPos = NOT_A_DICT_POS;
    180         }
    181     }
    182 
    183     // Read the parent node of the current node.
    184     AK_FORCE_INLINE void readParentNode() {
    185         if (mNodeReader.getParentPos() != NOT_A_DICT_POS) {
    186             mReadingState.mPrevTotalCodePointCount += mNodeReader.getCodePointCount();
    187             mReadingState.mTotalNodeCount = 1;
    188             mReadingState.mNodeArrayCount = 1;
    189             mReadingState.mNodeCount = 1;
    190             mReadingState.mPos = mNodeReader.getParentPos();
    191             mReadingState.mPosOfLastForwardLinkField = NOT_A_DICT_POS;
    192             mReadingState.mPosOfLastPtNodeArrayHead = NOT_A_DICT_POS;
    193             fetchPtNodeInfo();
    194         } else {
    195             mReadingState.mPos = NOT_A_DICT_POS;
    196         }
    197     }
    198 
    199     AK_FORCE_INLINE int getPosOfLastForwardLinkField() const {
    200         return mReadingState.mPosOfLastForwardLinkField;
    201     }
    202 
    203     AK_FORCE_INLINE int getPosOfLastPtNodeArrayHead() const {
    204         return mReadingState.mPosOfLastPtNodeArrayHead;
    205     }
    206 
    207     AK_FORCE_INLINE void reloadCurrentPtNodeInfo() {
    208         if (!isEnd()) {
    209             fetchPtNodeInfo();
    210         }
    211     }
    212 
    213     bool traverseAllPtNodesInPostorderDepthFirstManner(TraversingEventListener *const listener);
    214 
    215     bool traverseAllPtNodesInPtNodeArrayLevelPreorderDepthFirstManner(
    216             TraversingEventListener *const listener);
    217 
    218  private:
    219     DISALLOW_COPY_AND_ASSIGN(DynamicPatriciaTrieReadingHelper);
    220 
    221     class ReadingState {
    222      public:
    223         // Note that copy constructor and assignment operator are used for this class to use
    224         // std::vector.
    225         ReadingState() : mPos(NOT_A_DICT_POS), mNodeCount(0), mPrevTotalCodePointCount(0),
    226                 mTotalNodeCount(0), mNodeArrayCount(0), mPosOfLastForwardLinkField(NOT_A_DICT_POS),
    227                 mPosOfLastPtNodeArrayHead(NOT_A_DICT_POS) {}
    228 
    229         int mPos;
    230         // Node count of a node array.
    231         int mNodeCount;
    232         int mPrevTotalCodePointCount;
    233         int mTotalNodeCount;
    234         int mNodeArrayCount;
    235         int mPosOfLastForwardLinkField;
    236         int mPosOfLastPtNodeArrayHead;
    237     };
    238 
    239     static const int MAX_CHILD_COUNT_TO_AVOID_INFINITE_LOOP;
    240     static const int MAX_NODE_ARRAY_COUNT_TO_AVOID_INFINITE_LOOP;
    241     static const size_t MAX_READING_STATE_STACK_SIZE;
    242 
    243     // TODO: Introduce error code to track what caused the error.
    244     bool mIsError;
    245     ReadingState mReadingState;
    246     const BufferWithExtendableBuffer *const mBuffer;
    247     DynamicPatriciaTrieNodeReader mNodeReader;
    248     int mMergedNodeCodePoints[MAX_WORD_LENGTH];
    249     std::vector<ReadingState> mReadingStateStack;
    250 
    251     void nextPtNodeArray();
    252 
    253     void followForwardLink();
    254 
    255     AK_FORCE_INLINE void fetchPtNodeInfo() {
    256         mNodeReader.fetchNodeInfoInBufferFromPtNodePosAndGetNodeCodePoints(mReadingState.mPos,
    257                 MAX_WORD_LENGTH, mMergedNodeCodePoints);
    258         if (mNodeReader.getCodePointCount() <= 0) {
    259             // Empty node is not allowed.
    260             mIsError = true;
    261             mReadingState.mPos = NOT_A_DICT_POS;
    262         }
    263     }
    264 
    265     AK_FORCE_INLINE void pushReadingStateToStack() {
    266         if (mReadingStateStack.size() > MAX_READING_STATE_STACK_SIZE) {
    267             AKLOGI("Reading state stack overflow. Max size: %zd", MAX_READING_STATE_STACK_SIZE);
    268             ASSERT(false);
    269             mIsError = true;
    270             mReadingState.mPos = NOT_A_DICT_POS;
    271         } else {
    272             mReadingStateStack.push_back(mReadingState);
    273         }
    274     }
    275 
    276     AK_FORCE_INLINE void popReadingStateFromStack() {
    277         if (mReadingStateStack.empty()) {
    278             mReadingState.mPos = NOT_A_DICT_POS;
    279         } else {
    280             mReadingState = mReadingStateStack.back();
    281             mReadingStateStack.pop_back();
    282             if (!isEnd()) {
    283                 fetchPtNodeInfo();
    284             }
    285         }
    286     }
    287 };
    288 } // namespace latinime
    289 #endif /* LATINIME_DYNAMIC_PATRICIA_TRIE_READING_HELPER_H */
    290