blob: e9f108e25de7d693d5fac477627badfe63490c58 [file] [log] [blame]
Jean Chalard1059f272011-06-28 20:45:05 +09001/*
2 * Copyright (C) 2011 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_BINARY_FORMAT_H
18#define LATINIME_BINARY_FORMAT_H
19
20namespace latinime {
21
22class BinaryFormat {
23private:
24 const static int32_t MINIMAL_ONE_BYTE_CHARACTER_VALUE = 0x20;
25 const static int32_t CHARACTER_ARRAY_TERMINATOR = 0x1F;
26 const static int MULTIPLE_BYTE_CHARACTER_ADDITIONAL_SIZE = 2;
27
28public:
29 static int getGroupCountAndForwardPointer(const uint8_t* const dict, int* pos);
30 static uint8_t getFlagsAndForwardPointer(const uint8_t* const dict, int* pos);
31 static int32_t getCharCodeAndForwardPointer(const uint8_t* const dict, int* pos);
32 static int readFrequencyWithoutMovingPointer(const uint8_t* const dict, const int pos);
33 static int skipOtherCharacters(const uint8_t* const dict, const int pos);
34 static int skipAttributes(const uint8_t* const dict, const int pos);
35 static int skipChildrenPosition(const uint8_t flags, const int pos);
36 static int skipFrequency(const uint8_t flags, const int pos);
37 static int skipAllAttributes(const uint8_t* const dict, const uint8_t flags, const int pos);
38 static int skipChildrenPosAndAttributes(const uint8_t* const dict, const uint8_t flags,
39 const int pos);
40 static int readChildrenPosition(const uint8_t* const dict, const uint8_t flags, const int pos);
41 static bool hasChildrenInFlags(const uint8_t flags);
42 static int getAttributeAddressAndForwardPointer(const uint8_t* const dict, const uint8_t flags,
43 int *pos);
44};
45
46inline int BinaryFormat::getGroupCountAndForwardPointer(const uint8_t* const dict, int* pos) {
47 return dict[(*pos)++];
48}
49
50inline uint8_t BinaryFormat::getFlagsAndForwardPointer(const uint8_t* const dict, int* pos) {
51 return dict[(*pos)++];
52}
53
54inline int32_t BinaryFormat::getCharCodeAndForwardPointer(const uint8_t* const dict, int* pos) {
55 const int origin = *pos;
56 const int32_t character = dict[origin];
57 if (character < MINIMAL_ONE_BYTE_CHARACTER_VALUE) {
58 if (character == CHARACTER_ARRAY_TERMINATOR) {
59 *pos = origin + 1;
60 return NOT_A_CHARACTER;
61 } else {
62 *pos = origin + 3;
63 const int32_t char_1 = character << 16;
64 const int32_t char_2 = char_1 + (dict[origin + 1] << 8);
65 return char_2 + dict[origin + 2];
66 }
67 } else {
68 *pos = origin + 1;
69 return character;
70 }
71}
72
73inline int BinaryFormat::readFrequencyWithoutMovingPointer(const uint8_t* const dict,
74 const int pos) {
75 return dict[pos];
76}
77
78inline int BinaryFormat::skipOtherCharacters(const uint8_t* const dict, const int pos) {
79 int currentPos = pos;
80 int32_t character = dict[currentPos++];
81 while (CHARACTER_ARRAY_TERMINATOR != character) {
82 if (character < MINIMAL_ONE_BYTE_CHARACTER_VALUE) {
83 currentPos += MULTIPLE_BYTE_CHARACTER_ADDITIONAL_SIZE;
84 }
85 character = dict[currentPos++];
86 }
87 return currentPos;
88}
89
90static inline int attributeAddressSize(const uint8_t flags) {
91 static const int ATTRIBUTE_ADDRESS_SHIFT = 4;
92 return (flags & UnigramDictionary::MASK_ATTRIBUTE_ADDRESS_TYPE) >> ATTRIBUTE_ADDRESS_SHIFT;
93 /* Note: this is a value-dependant optimization of what may probably be
94 more readably written this way:
95 switch (flags * UnigramDictionary::MASK_ATTRIBUTE_ADDRESS_TYPE) {
96 case UnigramDictionary::FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE: return 1;
97 case UnigramDictionary::FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES: return 2;
98 case UnigramDictionary::FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTE: return 3;
99 default: return 0;
100 }
101 */
102}
103
104inline int BinaryFormat::skipAttributes(const uint8_t* const dict, const int pos) {
105 int currentPos = pos;
106 uint8_t flags = getFlagsAndForwardPointer(dict, &currentPos);
107 while (flags & UnigramDictionary::FLAG_ATTRIBUTE_HAS_NEXT) {
108 currentPos += attributeAddressSize(flags);
109 flags = getFlagsAndForwardPointer(dict, &currentPos);
110 }
111 currentPos += attributeAddressSize(flags);
112 return currentPos;
113}
114
115static inline int childrenAddressSize(const uint8_t flags) {
116 static const int CHILDREN_ADDRESS_SHIFT = 6;
117 return (UnigramDictionary::MASK_GROUP_ADDRESS_TYPE & flags) >> CHILDREN_ADDRESS_SHIFT;
118 /* See the note in attributeAddressSize. The same applies here */
119}
120
121inline int BinaryFormat::skipChildrenPosition(const uint8_t flags, const int pos) {
122 return pos + childrenAddressSize(flags);
123}
124
125inline int BinaryFormat::skipFrequency(const uint8_t flags, const int pos) {
126 return UnigramDictionary::FLAG_IS_TERMINAL & flags ? pos + 1 : pos;
127}
128
129inline int BinaryFormat::skipAllAttributes(const uint8_t* const dict, const uint8_t flags,
130 const int pos) {
131 // This function skips all attributes. The format makes provision for future extension
132 // with other attributes (notably shortcuts) but for the time being, bigrams are the
133 // only attributes that may be found in a character group, so we only look at bigrams
134 // in this version.
135 if (UnigramDictionary::FLAG_HAS_BIGRAMS & flags) {
136 return skipAttributes(dict, pos);
137 } else {
138 return pos;
139 }
140}
141
142inline int BinaryFormat::skipChildrenPosAndAttributes(const uint8_t* const dict,
143 const uint8_t flags, const int pos) {
144 int currentPos = pos;
145 currentPos = skipChildrenPosition(flags, currentPos);
146 currentPos = skipAllAttributes(dict, flags, currentPos);
147 return currentPos;
148}
149
150inline int BinaryFormat::readChildrenPosition(const uint8_t* const dict, const uint8_t flags,
151 const int pos) {
152 int offset = 0;
153 switch (UnigramDictionary::MASK_GROUP_ADDRESS_TYPE & flags) {
154 case UnigramDictionary::FLAG_GROUP_ADDRESS_TYPE_ONEBYTE:
155 offset = dict[pos];
156 break;
157 case UnigramDictionary::FLAG_GROUP_ADDRESS_TYPE_TWOBYTES:
158 offset = dict[pos] << 8;
159 offset += dict[pos + 1];
160 break;
161 case UnigramDictionary::FLAG_GROUP_ADDRESS_TYPE_THREEBYTES:
162 offset = dict[pos] << 16;
163 offset += dict[pos + 1] << 8;
164 offset += dict[pos + 2];
165 break;
166 default:
167 // If we come here, it means we asked for the children of a word with
168 // no children.
169 return -1;
170 }
171 return pos + offset;
172}
173
174inline bool BinaryFormat::hasChildrenInFlags(const uint8_t flags) {
175 return (UnigramDictionary::FLAG_GROUP_ADDRESS_TYPE_NOADDRESS
176 != (UnigramDictionary::MASK_GROUP_ADDRESS_TYPE & flags));
177}
178
179inline int BinaryFormat::getAttributeAddressAndForwardPointer(const uint8_t* const dict,
180 const uint8_t flags, int *pos) {
181 int offset = 0;
182 const int origin = *pos;
183 switch (UnigramDictionary::MASK_ATTRIBUTE_ADDRESS_TYPE & flags) {
184 case UnigramDictionary::FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE:
185 offset = dict[origin];
186 *pos = origin + 1;
187 break;
188 case UnigramDictionary::FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES:
189 offset = dict[origin] << 8;
190 offset += dict[origin + 1];
191 *pos = origin + 2;
192 break;
193 case UnigramDictionary::FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES:
194 offset = dict[origin] << 16;
195 offset += dict[origin + 1] << 8;
196 offset += dict[origin + 2];
197 *pos = origin + 3;
198 break;
199 }
200 if (UnigramDictionary::FLAG_ATTRIBUTE_OFFSET_NEGATIVE & flags) {
201 return origin - offset;
202 } else {
203 return origin + offset;
204 }
205}
206
207} // namespace latinime
208
209#endif // LATINIME_BINARY_FORMAT_H