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/v4/content/terminal_position_lookup_table.h"
18 
19 #include "dictionary/utils/buffer_with_extendable_buffer.h"
20 
21 namespace latinime {
22 
getTerminalPtNodePosition(const int terminalId) const23 int TerminalPositionLookupTable::getTerminalPtNodePosition(const int terminalId) const {
24     if (terminalId < 0 || terminalId >= mSize) {
25         return NOT_A_DICT_POS;
26     }
27     const int terminalPos = getBuffer()->readUint(
28             Ver4DictConstants::TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE, getEntryPos(terminalId));
29     return (terminalPos == Ver4DictConstants::NOT_A_TERMINAL_ADDRESS) ?
30             NOT_A_DICT_POS : terminalPos;
31 }
32 
setTerminalPtNodePosition(const int terminalId,const int terminalPtNodePos)33 bool TerminalPositionLookupTable::setTerminalPtNodePosition(
34         const int terminalId, const int terminalPtNodePos) {
35     if (terminalId < 0) {
36         return false;
37     }
38     while (terminalId >= mSize) {
39         // Write new entry.
40         if (!getWritableBuffer()->writeUint(Ver4DictConstants::NOT_A_TERMINAL_ADDRESS,
41                 Ver4DictConstants::TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE, getEntryPos(mSize))) {
42             return false;
43         }
44         mSize++;
45     }
46     const int terminalPos = (terminalPtNodePos != NOT_A_DICT_POS) ?
47             terminalPtNodePos : Ver4DictConstants::NOT_A_TERMINAL_ADDRESS;
48     return getWritableBuffer()->writeUint(terminalPos,
49             Ver4DictConstants::TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE, getEntryPos(terminalId));
50 }
51 
flushToFile(FILE * const file) const52 bool TerminalPositionLookupTable::flushToFile(FILE *const file) const {
53     // If the used buffer size is smaller than the actual buffer size, regenerate the lookup
54     // table and write the new table to the file.
55     if (getEntryPos(mSize) < getBuffer()->getTailPosition()) {
56         TerminalPositionLookupTable lookupTableToWrite;
57         for (int i = 0; i < mSize; ++i) {
58             const int terminalPtNodePosition = getTerminalPtNodePosition(i);
59             if (!lookupTableToWrite.setTerminalPtNodePosition(i, terminalPtNodePosition)) {
60                 AKLOGE("Cannot set terminal position to lookupTableToWrite."
61                         " terminalId: %d, position: %d", i, terminalPtNodePosition);
62                 return false;
63             }
64         }
65         return lookupTableToWrite.flush(file);
66     } else {
67         // We can simply use this lookup table because the buffer size has not been
68         // changed.
69         return flush(file);
70     }
71 }
72 
runGCTerminalIds(TerminalIdMap * const terminalIdMap)73 bool TerminalPositionLookupTable::runGCTerminalIds(TerminalIdMap *const terminalIdMap) {
74     int removedEntryCount = 0;
75     int nextNewTerminalId = 0;
76     for (int i = 0; i < mSize; ++i) {
77         const int terminalPos = getBuffer()->readUint(
78                 Ver4DictConstants::TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE, getEntryPos(i));
79         if (terminalPos == Ver4DictConstants::NOT_A_TERMINAL_ADDRESS) {
80             // This entry is a garbage.
81             removedEntryCount++;
82         } else {
83             // Give a new terminal id to the entry.
84             if (!getWritableBuffer()->writeUint(terminalPos,
85                     Ver4DictConstants::TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE,
86                     getEntryPos(nextNewTerminalId))) {
87                 return false;
88             }
89             // Memorize the mapping to the old terminal id to the new terminal id.
90             terminalIdMap->insert(TerminalIdMap::value_type(i, nextNewTerminalId));
91             nextNewTerminalId++;
92         }
93     }
94     mSize = nextNewTerminalId;
95     return true;
96 }
97 
98 } // namespace latinime
99