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#include "dictionary/structure/pt_common/dynamic_pt_gc_event_listeners.h"
18
19#include "dictionary/interface/dictionary_header_structure_policy.h"
20#include "dictionary/structure/pt_common/dynamic_pt_writing_utils.h"
21#include "dictionary/structure/pt_common/pt_node_params.h"
22#include "dictionary/structure/pt_common/pt_node_writer.h"
23
24namespace latinime {
25
26bool DynamicPtGcEventListeners
27        ::TraversePolicyToUpdateUnigramProbabilityAndMarkUselessPtNodesAsDeleted
28                ::onVisitingPtNode(const PtNodeParams *const ptNodeParams) {
29    // PtNode is useless when the PtNode is not a terminal and doesn't have any not useless
30    // children.
31    bool isUselessPtNode = !ptNodeParams->isTerminal();
32    if (ptNodeParams->isTerminal() && !ptNodeParams->representsNonWordInfo()) {
33        bool needsToKeepPtNode = true;
34        if (!mPtNodeWriter->updatePtNodeProbabilityAndGetNeedsToKeepPtNodeAfterGC(
35                ptNodeParams, &needsToKeepPtNode)) {
36            AKLOGE("Cannot update PtNode probability or get needs to keep PtNode after GC.");
37            return false;
38        }
39        if (!needsToKeepPtNode) {
40            isUselessPtNode = true;
41        }
42    }
43    if (mChildrenValue > 0) {
44        isUselessPtNode = false;
45    } else if (ptNodeParams->isTerminal()) {
46        // Remove children as all children are useless.
47        if (!mPtNodeWriter->updateChildrenPosition(ptNodeParams,
48                NOT_A_DICT_POS /* newChildrenPosition */)) {
49            return false;
50        }
51    }
52    if (isUselessPtNode) {
53        // Current PtNode is no longer needed. Mark it as deleted.
54        if (!mPtNodeWriter->markPtNodeAsDeleted(ptNodeParams)) {
55            return false;
56        }
57    } else {
58        mValueStack.back() += 1;
59        if (ptNodeParams->isTerminal() && !ptNodeParams->representsNonWordInfo()) {
60            mValidUnigramCount += 1;
61        }
62    }
63    return true;
64}
65
66bool DynamicPtGcEventListeners::TraversePolicyToUpdateBigramProbability
67        ::onVisitingPtNode(const PtNodeParams *const ptNodeParams) {
68    if (!ptNodeParams->isDeleted()) {
69        int bigramEntryCount = 0;
70        if (!mPtNodeWriter->updateAllBigramEntriesAndDeleteUselessEntries(ptNodeParams,
71                &bigramEntryCount)) {
72            return false;
73        }
74        mValidBigramEntryCount += bigramEntryCount;
75    }
76    return true;
77}
78
79// Writes dummy PtNode array size when the head of PtNode array is read.
80bool DynamicPtGcEventListeners::TraversePolicyToPlaceAndWriteValidPtNodesToBuffer
81        ::onDescend(const int ptNodeArrayPos) {
82    mValidPtNodeCount = 0;
83    int writingPos = mBufferToWrite->getTailPosition();
84    mDictPositionRelocationMap->mPtNodeArrayPositionRelocationMap.insert(
85            PtNodeWriter::PtNodeArrayPositionRelocationMap::value_type(ptNodeArrayPos, writingPos));
86    // Writes dummy PtNode array size because arrays can have a forward link or needles PtNodes.
87    // This field will be updated later in onReadingPtNodeArrayTail() with actual PtNode count.
88    mPtNodeArraySizeFieldPos = writingPos;
89    return DynamicPtWritingUtils::writePtNodeArraySizeAndAdvancePosition(
90            mBufferToWrite, 0 /* arraySize */, &writingPos);
91}
92
93// Write PtNode array terminal and actual PtNode array size.
94bool DynamicPtGcEventListeners::TraversePolicyToPlaceAndWriteValidPtNodesToBuffer
95        ::onReadingPtNodeArrayTail() {
96    int writingPos = mBufferToWrite->getTailPosition();
97    // Write PtNode array terminal.
98    if (!DynamicPtWritingUtils::writeForwardLinkPositionAndAdvancePosition(
99            mBufferToWrite, NOT_A_DICT_POS /* forwardLinkPos */, &writingPos)) {
100        return false;
101    }
102    // Write actual PtNode array size.
103    if (!DynamicPtWritingUtils::writePtNodeArraySizeAndAdvancePosition(
104            mBufferToWrite, mValidPtNodeCount, &mPtNodeArraySizeFieldPos)) {
105        return false;
106    }
107    return true;
108}
109
110// Write valid PtNode to buffer and memorize mapping from the old position to the new position.
111bool DynamicPtGcEventListeners::TraversePolicyToPlaceAndWriteValidPtNodesToBuffer
112        ::onVisitingPtNode(const PtNodeParams *const ptNodeParams) {
113    if (ptNodeParams->isDeleted()) {
114        // Current PtNode is not written in new buffer because it has been deleted.
115        mDictPositionRelocationMap->mPtNodePositionRelocationMap.insert(
116                PtNodeWriter::PtNodePositionRelocationMap::value_type(
117                        ptNodeParams->getHeadPos(), NOT_A_DICT_POS));
118        return true;
119    }
120    int writingPos = mBufferToWrite->getTailPosition();
121    mDictPositionRelocationMap->mPtNodePositionRelocationMap.insert(
122            PtNodeWriter::PtNodePositionRelocationMap::value_type(
123                    ptNodeParams->getHeadPos(), writingPos));
124    mValidPtNodeCount++;
125    // Writes current PtNode.
126    return mPtNodeWriter->writePtNodeAndAdvancePosition(ptNodeParams, &writingPos);
127}
128
129bool DynamicPtGcEventListeners::TraversePolicyToUpdateAllPositionFields
130        ::onVisitingPtNode(const PtNodeParams *const ptNodeParams) {
131    // Updates parent position.
132    int bigramCount = 0;
133    if (!mPtNodeWriter->updateAllPositionFields(ptNodeParams, mDictPositionRelocationMap,
134            &bigramCount)) {
135        return false;
136    }
137    mBigramCount += bigramCount;
138    if (ptNodeParams->isTerminal()) {
139        mUnigramCount++;
140    }
141    return true;
142}
143
144} // namespace latinime
145