1*0e209d39SAndroid Build Coastguard Worker // © 2017 and later: Unicode, Inc. and others.
2*0e209d39SAndroid Build Coastguard Worker // License & terms of use: http://www.unicode.org/copyright.html
3*0e209d39SAndroid Build Coastguard Worker
4*0e209d39SAndroid Build Coastguard Worker // ucptrie.cpp (modified from utrie2.cpp)
5*0e209d39SAndroid Build Coastguard Worker // created: 2017dec29 Markus W. Scherer
6*0e209d39SAndroid Build Coastguard Worker
7*0e209d39SAndroid Build Coastguard Worker // #define UCPTRIE_DEBUG
8*0e209d39SAndroid Build Coastguard Worker #ifdef UCPTRIE_DEBUG
9*0e209d39SAndroid Build Coastguard Worker # include <stdio.h>
10*0e209d39SAndroid Build Coastguard Worker #endif
11*0e209d39SAndroid Build Coastguard Worker
12*0e209d39SAndroid Build Coastguard Worker #include "unicode/utypes.h"
13*0e209d39SAndroid Build Coastguard Worker #include "unicode/ucptrie.h"
14*0e209d39SAndroid Build Coastguard Worker #include "unicode/utf.h"
15*0e209d39SAndroid Build Coastguard Worker #include "unicode/utf8.h"
16*0e209d39SAndroid Build Coastguard Worker #include "unicode/utf16.h"
17*0e209d39SAndroid Build Coastguard Worker #include "cmemory.h"
18*0e209d39SAndroid Build Coastguard Worker #include "uassert.h"
19*0e209d39SAndroid Build Coastguard Worker #include "ucptrie_impl.h"
20*0e209d39SAndroid Build Coastguard Worker
21*0e209d39SAndroid Build Coastguard Worker U_CAPI UCPTrie * U_EXPORT2
ucptrie_openFromBinary(UCPTrieType type,UCPTrieValueWidth valueWidth,const void * data,int32_t length,int32_t * pActualLength,UErrorCode * pErrorCode)22*0e209d39SAndroid Build Coastguard Worker ucptrie_openFromBinary(UCPTrieType type, UCPTrieValueWidth valueWidth,
23*0e209d39SAndroid Build Coastguard Worker const void *data, int32_t length, int32_t *pActualLength,
24*0e209d39SAndroid Build Coastguard Worker UErrorCode *pErrorCode) {
25*0e209d39SAndroid Build Coastguard Worker if (U_FAILURE(*pErrorCode)) {
26*0e209d39SAndroid Build Coastguard Worker return nullptr;
27*0e209d39SAndroid Build Coastguard Worker }
28*0e209d39SAndroid Build Coastguard Worker
29*0e209d39SAndroid Build Coastguard Worker if (length <= 0 || (U_POINTER_MASK_LSB(data, 3) != 0) ||
30*0e209d39SAndroid Build Coastguard Worker type < UCPTRIE_TYPE_ANY || UCPTRIE_TYPE_SMALL < type ||
31*0e209d39SAndroid Build Coastguard Worker valueWidth < UCPTRIE_VALUE_BITS_ANY || UCPTRIE_VALUE_BITS_8 < valueWidth) {
32*0e209d39SAndroid Build Coastguard Worker *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
33*0e209d39SAndroid Build Coastguard Worker return nullptr;
34*0e209d39SAndroid Build Coastguard Worker }
35*0e209d39SAndroid Build Coastguard Worker
36*0e209d39SAndroid Build Coastguard Worker // Enough data for a trie header?
37*0e209d39SAndroid Build Coastguard Worker if (length < (int32_t)sizeof(UCPTrieHeader)) {
38*0e209d39SAndroid Build Coastguard Worker *pErrorCode = U_INVALID_FORMAT_ERROR;
39*0e209d39SAndroid Build Coastguard Worker return nullptr;
40*0e209d39SAndroid Build Coastguard Worker }
41*0e209d39SAndroid Build Coastguard Worker
42*0e209d39SAndroid Build Coastguard Worker // Check the signature.
43*0e209d39SAndroid Build Coastguard Worker const UCPTrieHeader *header = (const UCPTrieHeader *)data;
44*0e209d39SAndroid Build Coastguard Worker if (header->signature != UCPTRIE_SIG) {
45*0e209d39SAndroid Build Coastguard Worker *pErrorCode = U_INVALID_FORMAT_ERROR;
46*0e209d39SAndroid Build Coastguard Worker return nullptr;
47*0e209d39SAndroid Build Coastguard Worker }
48*0e209d39SAndroid Build Coastguard Worker
49*0e209d39SAndroid Build Coastguard Worker int32_t options = header->options;
50*0e209d39SAndroid Build Coastguard Worker int32_t typeInt = (options >> 6) & 3;
51*0e209d39SAndroid Build Coastguard Worker int32_t valueWidthInt = options & UCPTRIE_OPTIONS_VALUE_BITS_MASK;
52*0e209d39SAndroid Build Coastguard Worker if (typeInt > UCPTRIE_TYPE_SMALL || valueWidthInt > UCPTRIE_VALUE_BITS_8 ||
53*0e209d39SAndroid Build Coastguard Worker (options & UCPTRIE_OPTIONS_RESERVED_MASK) != 0) {
54*0e209d39SAndroid Build Coastguard Worker *pErrorCode = U_INVALID_FORMAT_ERROR;
55*0e209d39SAndroid Build Coastguard Worker return nullptr;
56*0e209d39SAndroid Build Coastguard Worker }
57*0e209d39SAndroid Build Coastguard Worker UCPTrieType actualType = (UCPTrieType)typeInt;
58*0e209d39SAndroid Build Coastguard Worker UCPTrieValueWidth actualValueWidth = (UCPTrieValueWidth)valueWidthInt;
59*0e209d39SAndroid Build Coastguard Worker if (type < 0) {
60*0e209d39SAndroid Build Coastguard Worker type = actualType;
61*0e209d39SAndroid Build Coastguard Worker }
62*0e209d39SAndroid Build Coastguard Worker if (valueWidth < 0) {
63*0e209d39SAndroid Build Coastguard Worker valueWidth = actualValueWidth;
64*0e209d39SAndroid Build Coastguard Worker }
65*0e209d39SAndroid Build Coastguard Worker if (type != actualType || valueWidth != actualValueWidth) {
66*0e209d39SAndroid Build Coastguard Worker *pErrorCode = U_INVALID_FORMAT_ERROR;
67*0e209d39SAndroid Build Coastguard Worker return nullptr;
68*0e209d39SAndroid Build Coastguard Worker }
69*0e209d39SAndroid Build Coastguard Worker
70*0e209d39SAndroid Build Coastguard Worker // Get the length values and offsets.
71*0e209d39SAndroid Build Coastguard Worker UCPTrie tempTrie;
72*0e209d39SAndroid Build Coastguard Worker uprv_memset(&tempTrie, 0, sizeof(tempTrie));
73*0e209d39SAndroid Build Coastguard Worker tempTrie.indexLength = header->indexLength;
74*0e209d39SAndroid Build Coastguard Worker tempTrie.dataLength =
75*0e209d39SAndroid Build Coastguard Worker ((options & UCPTRIE_OPTIONS_DATA_LENGTH_MASK) << 4) | header->dataLength;
76*0e209d39SAndroid Build Coastguard Worker tempTrie.index3NullOffset = header->index3NullOffset;
77*0e209d39SAndroid Build Coastguard Worker tempTrie.dataNullOffset =
78*0e209d39SAndroid Build Coastguard Worker ((options & UCPTRIE_OPTIONS_DATA_NULL_OFFSET_MASK) << 8) | header->dataNullOffset;
79*0e209d39SAndroid Build Coastguard Worker
80*0e209d39SAndroid Build Coastguard Worker tempTrie.highStart = header->shiftedHighStart << UCPTRIE_SHIFT_2;
81*0e209d39SAndroid Build Coastguard Worker tempTrie.shifted12HighStart = (tempTrie.highStart + 0xfff) >> 12;
82*0e209d39SAndroid Build Coastguard Worker tempTrie.type = type;
83*0e209d39SAndroid Build Coastguard Worker tempTrie.valueWidth = valueWidth;
84*0e209d39SAndroid Build Coastguard Worker
85*0e209d39SAndroid Build Coastguard Worker // Calculate the actual length.
86*0e209d39SAndroid Build Coastguard Worker int32_t actualLength = (int32_t)sizeof(UCPTrieHeader) + tempTrie.indexLength * 2;
87*0e209d39SAndroid Build Coastguard Worker if (valueWidth == UCPTRIE_VALUE_BITS_16) {
88*0e209d39SAndroid Build Coastguard Worker actualLength += tempTrie.dataLength * 2;
89*0e209d39SAndroid Build Coastguard Worker } else if (valueWidth == UCPTRIE_VALUE_BITS_32) {
90*0e209d39SAndroid Build Coastguard Worker actualLength += tempTrie.dataLength * 4;
91*0e209d39SAndroid Build Coastguard Worker } else {
92*0e209d39SAndroid Build Coastguard Worker actualLength += tempTrie.dataLength;
93*0e209d39SAndroid Build Coastguard Worker }
94*0e209d39SAndroid Build Coastguard Worker if (length < actualLength) {
95*0e209d39SAndroid Build Coastguard Worker *pErrorCode = U_INVALID_FORMAT_ERROR; // Not enough bytes.
96*0e209d39SAndroid Build Coastguard Worker return nullptr;
97*0e209d39SAndroid Build Coastguard Worker }
98*0e209d39SAndroid Build Coastguard Worker
99*0e209d39SAndroid Build Coastguard Worker // Allocate the trie.
100*0e209d39SAndroid Build Coastguard Worker UCPTrie *trie = (UCPTrie *)uprv_malloc(sizeof(UCPTrie));
101*0e209d39SAndroid Build Coastguard Worker if (trie == nullptr) {
102*0e209d39SAndroid Build Coastguard Worker *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
103*0e209d39SAndroid Build Coastguard Worker return nullptr;
104*0e209d39SAndroid Build Coastguard Worker }
105*0e209d39SAndroid Build Coastguard Worker uprv_memcpy(trie, &tempTrie, sizeof(tempTrie));
106*0e209d39SAndroid Build Coastguard Worker #ifdef UCPTRIE_DEBUG
107*0e209d39SAndroid Build Coastguard Worker trie->name = "fromSerialized";
108*0e209d39SAndroid Build Coastguard Worker #endif
109*0e209d39SAndroid Build Coastguard Worker
110*0e209d39SAndroid Build Coastguard Worker // Set the pointers to its index and data arrays.
111*0e209d39SAndroid Build Coastguard Worker const uint16_t *p16 = (const uint16_t *)(header + 1);
112*0e209d39SAndroid Build Coastguard Worker trie->index = p16;
113*0e209d39SAndroid Build Coastguard Worker p16 += trie->indexLength;
114*0e209d39SAndroid Build Coastguard Worker
115*0e209d39SAndroid Build Coastguard Worker // Get the data.
116*0e209d39SAndroid Build Coastguard Worker int32_t nullValueOffset = trie->dataNullOffset;
117*0e209d39SAndroid Build Coastguard Worker if (nullValueOffset >= trie->dataLength) {
118*0e209d39SAndroid Build Coastguard Worker nullValueOffset = trie->dataLength - UCPTRIE_HIGH_VALUE_NEG_DATA_OFFSET;
119*0e209d39SAndroid Build Coastguard Worker }
120*0e209d39SAndroid Build Coastguard Worker switch (valueWidth) {
121*0e209d39SAndroid Build Coastguard Worker case UCPTRIE_VALUE_BITS_16:
122*0e209d39SAndroid Build Coastguard Worker trie->data.ptr16 = p16;
123*0e209d39SAndroid Build Coastguard Worker trie->nullValue = trie->data.ptr16[nullValueOffset];
124*0e209d39SAndroid Build Coastguard Worker break;
125*0e209d39SAndroid Build Coastguard Worker case UCPTRIE_VALUE_BITS_32:
126*0e209d39SAndroid Build Coastguard Worker trie->data.ptr32 = (const uint32_t *)p16;
127*0e209d39SAndroid Build Coastguard Worker trie->nullValue = trie->data.ptr32[nullValueOffset];
128*0e209d39SAndroid Build Coastguard Worker break;
129*0e209d39SAndroid Build Coastguard Worker case UCPTRIE_VALUE_BITS_8:
130*0e209d39SAndroid Build Coastguard Worker trie->data.ptr8 = (const uint8_t *)p16;
131*0e209d39SAndroid Build Coastguard Worker trie->nullValue = trie->data.ptr8[nullValueOffset];
132*0e209d39SAndroid Build Coastguard Worker break;
133*0e209d39SAndroid Build Coastguard Worker default:
134*0e209d39SAndroid Build Coastguard Worker // Unreachable because valueWidth was checked above.
135*0e209d39SAndroid Build Coastguard Worker *pErrorCode = U_INVALID_FORMAT_ERROR;
136*0e209d39SAndroid Build Coastguard Worker return nullptr;
137*0e209d39SAndroid Build Coastguard Worker }
138*0e209d39SAndroid Build Coastguard Worker
139*0e209d39SAndroid Build Coastguard Worker if (pActualLength != nullptr) {
140*0e209d39SAndroid Build Coastguard Worker *pActualLength = actualLength;
141*0e209d39SAndroid Build Coastguard Worker }
142*0e209d39SAndroid Build Coastguard Worker return trie;
143*0e209d39SAndroid Build Coastguard Worker }
144*0e209d39SAndroid Build Coastguard Worker
145*0e209d39SAndroid Build Coastguard Worker U_CAPI void U_EXPORT2
ucptrie_close(UCPTrie * trie)146*0e209d39SAndroid Build Coastguard Worker ucptrie_close(UCPTrie *trie) {
147*0e209d39SAndroid Build Coastguard Worker uprv_free(trie);
148*0e209d39SAndroid Build Coastguard Worker }
149*0e209d39SAndroid Build Coastguard Worker
150*0e209d39SAndroid Build Coastguard Worker U_CAPI UCPTrieType U_EXPORT2
ucptrie_getType(const UCPTrie * trie)151*0e209d39SAndroid Build Coastguard Worker ucptrie_getType(const UCPTrie *trie) {
152*0e209d39SAndroid Build Coastguard Worker return (UCPTrieType)trie->type;
153*0e209d39SAndroid Build Coastguard Worker }
154*0e209d39SAndroid Build Coastguard Worker
155*0e209d39SAndroid Build Coastguard Worker U_CAPI UCPTrieValueWidth U_EXPORT2
ucptrie_getValueWidth(const UCPTrie * trie)156*0e209d39SAndroid Build Coastguard Worker ucptrie_getValueWidth(const UCPTrie *trie) {
157*0e209d39SAndroid Build Coastguard Worker return (UCPTrieValueWidth)trie->valueWidth;
158*0e209d39SAndroid Build Coastguard Worker }
159*0e209d39SAndroid Build Coastguard Worker
160*0e209d39SAndroid Build Coastguard Worker U_CAPI int32_t U_EXPORT2
ucptrie_internalSmallIndex(const UCPTrie * trie,UChar32 c)161*0e209d39SAndroid Build Coastguard Worker ucptrie_internalSmallIndex(const UCPTrie *trie, UChar32 c) {
162*0e209d39SAndroid Build Coastguard Worker int32_t i1 = c >> UCPTRIE_SHIFT_1;
163*0e209d39SAndroid Build Coastguard Worker if (trie->type == UCPTRIE_TYPE_FAST) {
164*0e209d39SAndroid Build Coastguard Worker U_ASSERT(0xffff < c && c < trie->highStart);
165*0e209d39SAndroid Build Coastguard Worker i1 += UCPTRIE_BMP_INDEX_LENGTH - UCPTRIE_OMITTED_BMP_INDEX_1_LENGTH;
166*0e209d39SAndroid Build Coastguard Worker } else {
167*0e209d39SAndroid Build Coastguard Worker U_ASSERT((uint32_t)c < (uint32_t)trie->highStart && trie->highStart > UCPTRIE_SMALL_LIMIT);
168*0e209d39SAndroid Build Coastguard Worker i1 += UCPTRIE_SMALL_INDEX_LENGTH;
169*0e209d39SAndroid Build Coastguard Worker }
170*0e209d39SAndroid Build Coastguard Worker int32_t i3Block = trie->index[
171*0e209d39SAndroid Build Coastguard Worker (int32_t)trie->index[i1] + ((c >> UCPTRIE_SHIFT_2) & UCPTRIE_INDEX_2_MASK)];
172*0e209d39SAndroid Build Coastguard Worker int32_t i3 = (c >> UCPTRIE_SHIFT_3) & UCPTRIE_INDEX_3_MASK;
173*0e209d39SAndroid Build Coastguard Worker int32_t dataBlock;
174*0e209d39SAndroid Build Coastguard Worker if ((i3Block & 0x8000) == 0) {
175*0e209d39SAndroid Build Coastguard Worker // 16-bit indexes
176*0e209d39SAndroid Build Coastguard Worker dataBlock = trie->index[i3Block + i3];
177*0e209d39SAndroid Build Coastguard Worker } else {
178*0e209d39SAndroid Build Coastguard Worker // 18-bit indexes stored in groups of 9 entries per 8 indexes.
179*0e209d39SAndroid Build Coastguard Worker i3Block = (i3Block & 0x7fff) + (i3 & ~7) + (i3 >> 3);
180*0e209d39SAndroid Build Coastguard Worker i3 &= 7;
181*0e209d39SAndroid Build Coastguard Worker dataBlock = ((int32_t)trie->index[i3Block++] << (2 + (2 * i3))) & 0x30000;
182*0e209d39SAndroid Build Coastguard Worker dataBlock |= trie->index[i3Block + i3];
183*0e209d39SAndroid Build Coastguard Worker }
184*0e209d39SAndroid Build Coastguard Worker return dataBlock + (c & UCPTRIE_SMALL_DATA_MASK);
185*0e209d39SAndroid Build Coastguard Worker }
186*0e209d39SAndroid Build Coastguard Worker
187*0e209d39SAndroid Build Coastguard Worker U_CAPI int32_t U_EXPORT2
ucptrie_internalSmallU8Index(const UCPTrie * trie,int32_t lt1,uint8_t t2,uint8_t t3)188*0e209d39SAndroid Build Coastguard Worker ucptrie_internalSmallU8Index(const UCPTrie *trie, int32_t lt1, uint8_t t2, uint8_t t3) {
189*0e209d39SAndroid Build Coastguard Worker UChar32 c = (lt1 << 12) | (t2 << 6) | t3;
190*0e209d39SAndroid Build Coastguard Worker if (c >= trie->highStart) {
191*0e209d39SAndroid Build Coastguard Worker // Possible because the UTF-8 macro compares with shifted12HighStart which may be higher.
192*0e209d39SAndroid Build Coastguard Worker return trie->dataLength - UCPTRIE_HIGH_VALUE_NEG_DATA_OFFSET;
193*0e209d39SAndroid Build Coastguard Worker }
194*0e209d39SAndroid Build Coastguard Worker return ucptrie_internalSmallIndex(trie, c);
195*0e209d39SAndroid Build Coastguard Worker }
196*0e209d39SAndroid Build Coastguard Worker
197*0e209d39SAndroid Build Coastguard Worker U_CAPI int32_t U_EXPORT2
ucptrie_internalU8PrevIndex(const UCPTrie * trie,UChar32 c,const uint8_t * start,const uint8_t * src)198*0e209d39SAndroid Build Coastguard Worker ucptrie_internalU8PrevIndex(const UCPTrie *trie, UChar32 c,
199*0e209d39SAndroid Build Coastguard Worker const uint8_t *start, const uint8_t *src) {
200*0e209d39SAndroid Build Coastguard Worker int32_t i, length;
201*0e209d39SAndroid Build Coastguard Worker // Support 64-bit pointers by avoiding cast of arbitrary difference.
202*0e209d39SAndroid Build Coastguard Worker if ((src - start) <= 7) {
203*0e209d39SAndroid Build Coastguard Worker i = length = (int32_t)(src - start);
204*0e209d39SAndroid Build Coastguard Worker } else {
205*0e209d39SAndroid Build Coastguard Worker i = length = 7;
206*0e209d39SAndroid Build Coastguard Worker start = src - 7;
207*0e209d39SAndroid Build Coastguard Worker }
208*0e209d39SAndroid Build Coastguard Worker c = utf8_prevCharSafeBody(start, 0, &i, c, -1);
209*0e209d39SAndroid Build Coastguard Worker i = length - i; // Number of bytes read backward from src.
210*0e209d39SAndroid Build Coastguard Worker int32_t idx = _UCPTRIE_CP_INDEX(trie, 0xffff, c);
211*0e209d39SAndroid Build Coastguard Worker return (idx << 3) | i;
212*0e209d39SAndroid Build Coastguard Worker }
213*0e209d39SAndroid Build Coastguard Worker
214*0e209d39SAndroid Build Coastguard Worker namespace {
215*0e209d39SAndroid Build Coastguard Worker
getValue(UCPTrieData data,UCPTrieValueWidth valueWidth,int32_t dataIndex)216*0e209d39SAndroid Build Coastguard Worker inline uint32_t getValue(UCPTrieData data, UCPTrieValueWidth valueWidth, int32_t dataIndex) {
217*0e209d39SAndroid Build Coastguard Worker switch (valueWidth) {
218*0e209d39SAndroid Build Coastguard Worker case UCPTRIE_VALUE_BITS_16:
219*0e209d39SAndroid Build Coastguard Worker return data.ptr16[dataIndex];
220*0e209d39SAndroid Build Coastguard Worker case UCPTRIE_VALUE_BITS_32:
221*0e209d39SAndroid Build Coastguard Worker return data.ptr32[dataIndex];
222*0e209d39SAndroid Build Coastguard Worker case UCPTRIE_VALUE_BITS_8:
223*0e209d39SAndroid Build Coastguard Worker return data.ptr8[dataIndex];
224*0e209d39SAndroid Build Coastguard Worker default:
225*0e209d39SAndroid Build Coastguard Worker // Unreachable if the trie is properly initialized.
226*0e209d39SAndroid Build Coastguard Worker return 0xffffffff;
227*0e209d39SAndroid Build Coastguard Worker }
228*0e209d39SAndroid Build Coastguard Worker }
229*0e209d39SAndroid Build Coastguard Worker
230*0e209d39SAndroid Build Coastguard Worker } // namespace
231*0e209d39SAndroid Build Coastguard Worker
232*0e209d39SAndroid Build Coastguard Worker U_CAPI uint32_t U_EXPORT2
ucptrie_get(const UCPTrie * trie,UChar32 c)233*0e209d39SAndroid Build Coastguard Worker ucptrie_get(const UCPTrie *trie, UChar32 c) {
234*0e209d39SAndroid Build Coastguard Worker int32_t dataIndex;
235*0e209d39SAndroid Build Coastguard Worker if ((uint32_t)c <= 0x7f) {
236*0e209d39SAndroid Build Coastguard Worker // linear ASCII
237*0e209d39SAndroid Build Coastguard Worker dataIndex = c;
238*0e209d39SAndroid Build Coastguard Worker } else {
239*0e209d39SAndroid Build Coastguard Worker UChar32 fastMax = trie->type == UCPTRIE_TYPE_FAST ? 0xffff : UCPTRIE_SMALL_MAX;
240*0e209d39SAndroid Build Coastguard Worker dataIndex = _UCPTRIE_CP_INDEX(trie, fastMax, c);
241*0e209d39SAndroid Build Coastguard Worker }
242*0e209d39SAndroid Build Coastguard Worker return getValue(trie->data, (UCPTrieValueWidth)trie->valueWidth, dataIndex);
243*0e209d39SAndroid Build Coastguard Worker }
244*0e209d39SAndroid Build Coastguard Worker
245*0e209d39SAndroid Build Coastguard Worker namespace {
246*0e209d39SAndroid Build Coastguard Worker
247*0e209d39SAndroid Build Coastguard Worker constexpr int32_t MAX_UNICODE = 0x10ffff;
248*0e209d39SAndroid Build Coastguard Worker
maybeFilterValue(uint32_t value,uint32_t trieNullValue,uint32_t nullValue,UCPMapValueFilter * filter,const void * context)249*0e209d39SAndroid Build Coastguard Worker inline uint32_t maybeFilterValue(uint32_t value, uint32_t trieNullValue, uint32_t nullValue,
250*0e209d39SAndroid Build Coastguard Worker UCPMapValueFilter *filter, const void *context) {
251*0e209d39SAndroid Build Coastguard Worker if (value == trieNullValue) {
252*0e209d39SAndroid Build Coastguard Worker value = nullValue;
253*0e209d39SAndroid Build Coastguard Worker } else if (filter != nullptr) {
254*0e209d39SAndroid Build Coastguard Worker value = filter(context, value);
255*0e209d39SAndroid Build Coastguard Worker }
256*0e209d39SAndroid Build Coastguard Worker return value;
257*0e209d39SAndroid Build Coastguard Worker }
258*0e209d39SAndroid Build Coastguard Worker
getRange(const void * t,UChar32 start,UCPMapValueFilter * filter,const void * context,uint32_t * pValue)259*0e209d39SAndroid Build Coastguard Worker UChar32 getRange(const void *t, UChar32 start,
260*0e209d39SAndroid Build Coastguard Worker UCPMapValueFilter *filter, const void *context, uint32_t *pValue) {
261*0e209d39SAndroid Build Coastguard Worker if ((uint32_t)start > MAX_UNICODE) {
262*0e209d39SAndroid Build Coastguard Worker return U_SENTINEL;
263*0e209d39SAndroid Build Coastguard Worker }
264*0e209d39SAndroid Build Coastguard Worker const UCPTrie *trie = reinterpret_cast<const UCPTrie *>(t);
265*0e209d39SAndroid Build Coastguard Worker UCPTrieValueWidth valueWidth = (UCPTrieValueWidth)trie->valueWidth;
266*0e209d39SAndroid Build Coastguard Worker if (start >= trie->highStart) {
267*0e209d39SAndroid Build Coastguard Worker if (pValue != nullptr) {
268*0e209d39SAndroid Build Coastguard Worker int32_t di = trie->dataLength - UCPTRIE_HIGH_VALUE_NEG_DATA_OFFSET;
269*0e209d39SAndroid Build Coastguard Worker uint32_t value = getValue(trie->data, valueWidth, di);
270*0e209d39SAndroid Build Coastguard Worker if (filter != nullptr) { value = filter(context, value); }
271*0e209d39SAndroid Build Coastguard Worker *pValue = value;
272*0e209d39SAndroid Build Coastguard Worker }
273*0e209d39SAndroid Build Coastguard Worker return MAX_UNICODE;
274*0e209d39SAndroid Build Coastguard Worker }
275*0e209d39SAndroid Build Coastguard Worker
276*0e209d39SAndroid Build Coastguard Worker uint32_t nullValue = trie->nullValue;
277*0e209d39SAndroid Build Coastguard Worker if (filter != nullptr) { nullValue = filter(context, nullValue); }
278*0e209d39SAndroid Build Coastguard Worker const uint16_t *index = trie->index;
279*0e209d39SAndroid Build Coastguard Worker
280*0e209d39SAndroid Build Coastguard Worker int32_t prevI3Block = -1;
281*0e209d39SAndroid Build Coastguard Worker int32_t prevBlock = -1;
282*0e209d39SAndroid Build Coastguard Worker UChar32 c = start;
283*0e209d39SAndroid Build Coastguard Worker uint32_t trieValue, value = nullValue;
284*0e209d39SAndroid Build Coastguard Worker bool haveValue = false;
285*0e209d39SAndroid Build Coastguard Worker do {
286*0e209d39SAndroid Build Coastguard Worker int32_t i3Block;
287*0e209d39SAndroid Build Coastguard Worker int32_t i3;
288*0e209d39SAndroid Build Coastguard Worker int32_t i3BlockLength;
289*0e209d39SAndroid Build Coastguard Worker int32_t dataBlockLength;
290*0e209d39SAndroid Build Coastguard Worker if (c <= 0xffff && (trie->type == UCPTRIE_TYPE_FAST || c <= UCPTRIE_SMALL_MAX)) {
291*0e209d39SAndroid Build Coastguard Worker i3Block = 0;
292*0e209d39SAndroid Build Coastguard Worker i3 = c >> UCPTRIE_FAST_SHIFT;
293*0e209d39SAndroid Build Coastguard Worker i3BlockLength = trie->type == UCPTRIE_TYPE_FAST ?
294*0e209d39SAndroid Build Coastguard Worker UCPTRIE_BMP_INDEX_LENGTH : UCPTRIE_SMALL_INDEX_LENGTH;
295*0e209d39SAndroid Build Coastguard Worker dataBlockLength = UCPTRIE_FAST_DATA_BLOCK_LENGTH;
296*0e209d39SAndroid Build Coastguard Worker } else {
297*0e209d39SAndroid Build Coastguard Worker // Use the multi-stage index.
298*0e209d39SAndroid Build Coastguard Worker int32_t i1 = c >> UCPTRIE_SHIFT_1;
299*0e209d39SAndroid Build Coastguard Worker if (trie->type == UCPTRIE_TYPE_FAST) {
300*0e209d39SAndroid Build Coastguard Worker U_ASSERT(0xffff < c && c < trie->highStart);
301*0e209d39SAndroid Build Coastguard Worker i1 += UCPTRIE_BMP_INDEX_LENGTH - UCPTRIE_OMITTED_BMP_INDEX_1_LENGTH;
302*0e209d39SAndroid Build Coastguard Worker } else {
303*0e209d39SAndroid Build Coastguard Worker U_ASSERT(c < trie->highStart && trie->highStart > UCPTRIE_SMALL_LIMIT);
304*0e209d39SAndroid Build Coastguard Worker i1 += UCPTRIE_SMALL_INDEX_LENGTH;
305*0e209d39SAndroid Build Coastguard Worker }
306*0e209d39SAndroid Build Coastguard Worker i3Block = trie->index[
307*0e209d39SAndroid Build Coastguard Worker (int32_t)trie->index[i1] + ((c >> UCPTRIE_SHIFT_2) & UCPTRIE_INDEX_2_MASK)];
308*0e209d39SAndroid Build Coastguard Worker if (i3Block == prevI3Block && (c - start) >= UCPTRIE_CP_PER_INDEX_2_ENTRY) {
309*0e209d39SAndroid Build Coastguard Worker // The index-3 block is the same as the previous one, and filled with value.
310*0e209d39SAndroid Build Coastguard Worker U_ASSERT((c & (UCPTRIE_CP_PER_INDEX_2_ENTRY - 1)) == 0);
311*0e209d39SAndroid Build Coastguard Worker c += UCPTRIE_CP_PER_INDEX_2_ENTRY;
312*0e209d39SAndroid Build Coastguard Worker continue;
313*0e209d39SAndroid Build Coastguard Worker }
314*0e209d39SAndroid Build Coastguard Worker prevI3Block = i3Block;
315*0e209d39SAndroid Build Coastguard Worker if (i3Block == trie->index3NullOffset) {
316*0e209d39SAndroid Build Coastguard Worker // This is the index-3 null block.
317*0e209d39SAndroid Build Coastguard Worker if (haveValue) {
318*0e209d39SAndroid Build Coastguard Worker if (nullValue != value) {
319*0e209d39SAndroid Build Coastguard Worker return c - 1;
320*0e209d39SAndroid Build Coastguard Worker }
321*0e209d39SAndroid Build Coastguard Worker } else {
322*0e209d39SAndroid Build Coastguard Worker trieValue = trie->nullValue;
323*0e209d39SAndroid Build Coastguard Worker value = nullValue;
324*0e209d39SAndroid Build Coastguard Worker if (pValue != nullptr) { *pValue = nullValue; }
325*0e209d39SAndroid Build Coastguard Worker haveValue = true;
326*0e209d39SAndroid Build Coastguard Worker }
327*0e209d39SAndroid Build Coastguard Worker prevBlock = trie->dataNullOffset;
328*0e209d39SAndroid Build Coastguard Worker c = (c + UCPTRIE_CP_PER_INDEX_2_ENTRY) & ~(UCPTRIE_CP_PER_INDEX_2_ENTRY - 1);
329*0e209d39SAndroid Build Coastguard Worker continue;
330*0e209d39SAndroid Build Coastguard Worker }
331*0e209d39SAndroid Build Coastguard Worker i3 = (c >> UCPTRIE_SHIFT_3) & UCPTRIE_INDEX_3_MASK;
332*0e209d39SAndroid Build Coastguard Worker i3BlockLength = UCPTRIE_INDEX_3_BLOCK_LENGTH;
333*0e209d39SAndroid Build Coastguard Worker dataBlockLength = UCPTRIE_SMALL_DATA_BLOCK_LENGTH;
334*0e209d39SAndroid Build Coastguard Worker }
335*0e209d39SAndroid Build Coastguard Worker // Enumerate data blocks for one index-3 block.
336*0e209d39SAndroid Build Coastguard Worker do {
337*0e209d39SAndroid Build Coastguard Worker int32_t block;
338*0e209d39SAndroid Build Coastguard Worker if ((i3Block & 0x8000) == 0) {
339*0e209d39SAndroid Build Coastguard Worker block = index[i3Block + i3];
340*0e209d39SAndroid Build Coastguard Worker } else {
341*0e209d39SAndroid Build Coastguard Worker // 18-bit indexes stored in groups of 9 entries per 8 indexes.
342*0e209d39SAndroid Build Coastguard Worker int32_t group = (i3Block & 0x7fff) + (i3 & ~7) + (i3 >> 3);
343*0e209d39SAndroid Build Coastguard Worker int32_t gi = i3 & 7;
344*0e209d39SAndroid Build Coastguard Worker block = ((int32_t)index[group++] << (2 + (2 * gi))) & 0x30000;
345*0e209d39SAndroid Build Coastguard Worker block |= index[group + gi];
346*0e209d39SAndroid Build Coastguard Worker }
347*0e209d39SAndroid Build Coastguard Worker if (block == prevBlock && (c - start) >= dataBlockLength) {
348*0e209d39SAndroid Build Coastguard Worker // The block is the same as the previous one, and filled with value.
349*0e209d39SAndroid Build Coastguard Worker U_ASSERT((c & (dataBlockLength - 1)) == 0);
350*0e209d39SAndroid Build Coastguard Worker c += dataBlockLength;
351*0e209d39SAndroid Build Coastguard Worker } else {
352*0e209d39SAndroid Build Coastguard Worker int32_t dataMask = dataBlockLength - 1;
353*0e209d39SAndroid Build Coastguard Worker prevBlock = block;
354*0e209d39SAndroid Build Coastguard Worker if (block == trie->dataNullOffset) {
355*0e209d39SAndroid Build Coastguard Worker // This is the data null block.
356*0e209d39SAndroid Build Coastguard Worker if (haveValue) {
357*0e209d39SAndroid Build Coastguard Worker if (nullValue != value) {
358*0e209d39SAndroid Build Coastguard Worker return c - 1;
359*0e209d39SAndroid Build Coastguard Worker }
360*0e209d39SAndroid Build Coastguard Worker } else {
361*0e209d39SAndroid Build Coastguard Worker trieValue = trie->nullValue;
362*0e209d39SAndroid Build Coastguard Worker value = nullValue;
363*0e209d39SAndroid Build Coastguard Worker if (pValue != nullptr) { *pValue = nullValue; }
364*0e209d39SAndroid Build Coastguard Worker haveValue = true;
365*0e209d39SAndroid Build Coastguard Worker }
366*0e209d39SAndroid Build Coastguard Worker c = (c + dataBlockLength) & ~dataMask;
367*0e209d39SAndroid Build Coastguard Worker } else {
368*0e209d39SAndroid Build Coastguard Worker int32_t di = block + (c & dataMask);
369*0e209d39SAndroid Build Coastguard Worker uint32_t trieValue2 = getValue(trie->data, valueWidth, di);
370*0e209d39SAndroid Build Coastguard Worker if (haveValue) {
371*0e209d39SAndroid Build Coastguard Worker if (trieValue2 != trieValue) {
372*0e209d39SAndroid Build Coastguard Worker if (filter == nullptr ||
373*0e209d39SAndroid Build Coastguard Worker maybeFilterValue(trieValue2, trie->nullValue, nullValue,
374*0e209d39SAndroid Build Coastguard Worker filter, context) != value) {
375*0e209d39SAndroid Build Coastguard Worker return c - 1;
376*0e209d39SAndroid Build Coastguard Worker }
377*0e209d39SAndroid Build Coastguard Worker trieValue = trieValue2; // may or may not help
378*0e209d39SAndroid Build Coastguard Worker }
379*0e209d39SAndroid Build Coastguard Worker } else {
380*0e209d39SAndroid Build Coastguard Worker trieValue = trieValue2;
381*0e209d39SAndroid Build Coastguard Worker value = maybeFilterValue(trieValue2, trie->nullValue, nullValue,
382*0e209d39SAndroid Build Coastguard Worker filter, context);
383*0e209d39SAndroid Build Coastguard Worker if (pValue != nullptr) { *pValue = value; }
384*0e209d39SAndroid Build Coastguard Worker haveValue = true;
385*0e209d39SAndroid Build Coastguard Worker }
386*0e209d39SAndroid Build Coastguard Worker while ((++c & dataMask) != 0) {
387*0e209d39SAndroid Build Coastguard Worker trieValue2 = getValue(trie->data, valueWidth, ++di);
388*0e209d39SAndroid Build Coastguard Worker if (trieValue2 != trieValue) {
389*0e209d39SAndroid Build Coastguard Worker if (filter == nullptr ||
390*0e209d39SAndroid Build Coastguard Worker maybeFilterValue(trieValue2, trie->nullValue, nullValue,
391*0e209d39SAndroid Build Coastguard Worker filter, context) != value) {
392*0e209d39SAndroid Build Coastguard Worker return c - 1;
393*0e209d39SAndroid Build Coastguard Worker }
394*0e209d39SAndroid Build Coastguard Worker trieValue = trieValue2; // may or may not help
395*0e209d39SAndroid Build Coastguard Worker }
396*0e209d39SAndroid Build Coastguard Worker }
397*0e209d39SAndroid Build Coastguard Worker }
398*0e209d39SAndroid Build Coastguard Worker }
399*0e209d39SAndroid Build Coastguard Worker } while (++i3 < i3BlockLength);
400*0e209d39SAndroid Build Coastguard Worker } while (c < trie->highStart);
401*0e209d39SAndroid Build Coastguard Worker U_ASSERT(haveValue);
402*0e209d39SAndroid Build Coastguard Worker int32_t di = trie->dataLength - UCPTRIE_HIGH_VALUE_NEG_DATA_OFFSET;
403*0e209d39SAndroid Build Coastguard Worker uint32_t highValue = getValue(trie->data, valueWidth, di);
404*0e209d39SAndroid Build Coastguard Worker if (maybeFilterValue(highValue, trie->nullValue, nullValue,
405*0e209d39SAndroid Build Coastguard Worker filter, context) != value) {
406*0e209d39SAndroid Build Coastguard Worker return c - 1;
407*0e209d39SAndroid Build Coastguard Worker } else {
408*0e209d39SAndroid Build Coastguard Worker return MAX_UNICODE;
409*0e209d39SAndroid Build Coastguard Worker }
410*0e209d39SAndroid Build Coastguard Worker }
411*0e209d39SAndroid Build Coastguard Worker
412*0e209d39SAndroid Build Coastguard Worker } // namespace
413*0e209d39SAndroid Build Coastguard Worker
414*0e209d39SAndroid Build Coastguard Worker U_CFUNC UChar32
ucptrie_internalGetRange(UCPTrieGetRange * getRange,const void * trie,UChar32 start,UCPMapRangeOption option,uint32_t surrogateValue,UCPMapValueFilter * filter,const void * context,uint32_t * pValue)415*0e209d39SAndroid Build Coastguard Worker ucptrie_internalGetRange(UCPTrieGetRange *getRange,
416*0e209d39SAndroid Build Coastguard Worker const void *trie, UChar32 start,
417*0e209d39SAndroid Build Coastguard Worker UCPMapRangeOption option, uint32_t surrogateValue,
418*0e209d39SAndroid Build Coastguard Worker UCPMapValueFilter *filter, const void *context, uint32_t *pValue) {
419*0e209d39SAndroid Build Coastguard Worker if (option == UCPMAP_RANGE_NORMAL) {
420*0e209d39SAndroid Build Coastguard Worker return getRange(trie, start, filter, context, pValue);
421*0e209d39SAndroid Build Coastguard Worker }
422*0e209d39SAndroid Build Coastguard Worker uint32_t value;
423*0e209d39SAndroid Build Coastguard Worker if (pValue == nullptr) {
424*0e209d39SAndroid Build Coastguard Worker // We need to examine the range value even if the caller does not want it.
425*0e209d39SAndroid Build Coastguard Worker pValue = &value;
426*0e209d39SAndroid Build Coastguard Worker }
427*0e209d39SAndroid Build Coastguard Worker UChar32 surrEnd = option == UCPMAP_RANGE_FIXED_ALL_SURROGATES ? 0xdfff : 0xdbff;
428*0e209d39SAndroid Build Coastguard Worker UChar32 end = getRange(trie, start, filter, context, pValue);
429*0e209d39SAndroid Build Coastguard Worker if (end < 0xd7ff || start > surrEnd) {
430*0e209d39SAndroid Build Coastguard Worker return end;
431*0e209d39SAndroid Build Coastguard Worker }
432*0e209d39SAndroid Build Coastguard Worker // The range overlaps with surrogates, or ends just before the first one.
433*0e209d39SAndroid Build Coastguard Worker if (*pValue == surrogateValue) {
434*0e209d39SAndroid Build Coastguard Worker if (end >= surrEnd) {
435*0e209d39SAndroid Build Coastguard Worker // Surrogates followed by a non-surrogateValue range,
436*0e209d39SAndroid Build Coastguard Worker // or surrogates are part of a larger surrogateValue range.
437*0e209d39SAndroid Build Coastguard Worker return end;
438*0e209d39SAndroid Build Coastguard Worker }
439*0e209d39SAndroid Build Coastguard Worker } else {
440*0e209d39SAndroid Build Coastguard Worker if (start <= 0xd7ff) {
441*0e209d39SAndroid Build Coastguard Worker return 0xd7ff; // Non-surrogateValue range ends before surrogateValue surrogates.
442*0e209d39SAndroid Build Coastguard Worker }
443*0e209d39SAndroid Build Coastguard Worker // Start is a surrogate with a non-surrogateValue code *unit* value.
444*0e209d39SAndroid Build Coastguard Worker // Return a surrogateValue code *point* range.
445*0e209d39SAndroid Build Coastguard Worker *pValue = surrogateValue;
446*0e209d39SAndroid Build Coastguard Worker if (end > surrEnd) {
447*0e209d39SAndroid Build Coastguard Worker return surrEnd; // Surrogate range ends before non-surrogateValue rest of range.
448*0e209d39SAndroid Build Coastguard Worker }
449*0e209d39SAndroid Build Coastguard Worker }
450*0e209d39SAndroid Build Coastguard Worker // See if the surrogateValue surrogate range can be merged with
451*0e209d39SAndroid Build Coastguard Worker // an immediately following range.
452*0e209d39SAndroid Build Coastguard Worker uint32_t value2;
453*0e209d39SAndroid Build Coastguard Worker UChar32 end2 = getRange(trie, surrEnd + 1, filter, context, &value2);
454*0e209d39SAndroid Build Coastguard Worker if (value2 == surrogateValue) {
455*0e209d39SAndroid Build Coastguard Worker return end2;
456*0e209d39SAndroid Build Coastguard Worker }
457*0e209d39SAndroid Build Coastguard Worker return surrEnd;
458*0e209d39SAndroid Build Coastguard Worker }
459*0e209d39SAndroid Build Coastguard Worker
460*0e209d39SAndroid Build Coastguard Worker U_CAPI UChar32 U_EXPORT2
ucptrie_getRange(const UCPTrie * trie,UChar32 start,UCPMapRangeOption option,uint32_t surrogateValue,UCPMapValueFilter * filter,const void * context,uint32_t * pValue)461*0e209d39SAndroid Build Coastguard Worker ucptrie_getRange(const UCPTrie *trie, UChar32 start,
462*0e209d39SAndroid Build Coastguard Worker UCPMapRangeOption option, uint32_t surrogateValue,
463*0e209d39SAndroid Build Coastguard Worker UCPMapValueFilter *filter, const void *context, uint32_t *pValue) {
464*0e209d39SAndroid Build Coastguard Worker return ucptrie_internalGetRange(getRange, trie, start,
465*0e209d39SAndroid Build Coastguard Worker option, surrogateValue,
466*0e209d39SAndroid Build Coastguard Worker filter, context, pValue);
467*0e209d39SAndroid Build Coastguard Worker }
468*0e209d39SAndroid Build Coastguard Worker
469*0e209d39SAndroid Build Coastguard Worker U_CAPI int32_t U_EXPORT2
ucptrie_toBinary(const UCPTrie * trie,void * data,int32_t capacity,UErrorCode * pErrorCode)470*0e209d39SAndroid Build Coastguard Worker ucptrie_toBinary(const UCPTrie *trie,
471*0e209d39SAndroid Build Coastguard Worker void *data, int32_t capacity,
472*0e209d39SAndroid Build Coastguard Worker UErrorCode *pErrorCode) {
473*0e209d39SAndroid Build Coastguard Worker if (U_FAILURE(*pErrorCode)) {
474*0e209d39SAndroid Build Coastguard Worker return 0;
475*0e209d39SAndroid Build Coastguard Worker }
476*0e209d39SAndroid Build Coastguard Worker
477*0e209d39SAndroid Build Coastguard Worker UCPTrieType type = (UCPTrieType)trie->type;
478*0e209d39SAndroid Build Coastguard Worker UCPTrieValueWidth valueWidth = (UCPTrieValueWidth)trie->valueWidth;
479*0e209d39SAndroid Build Coastguard Worker if (type < UCPTRIE_TYPE_FAST || UCPTRIE_TYPE_SMALL < type ||
480*0e209d39SAndroid Build Coastguard Worker valueWidth < UCPTRIE_VALUE_BITS_16 || UCPTRIE_VALUE_BITS_8 < valueWidth ||
481*0e209d39SAndroid Build Coastguard Worker capacity < 0 ||
482*0e209d39SAndroid Build Coastguard Worker (capacity > 0 && (data == nullptr || (U_POINTER_MASK_LSB(data, 3) != 0)))) {
483*0e209d39SAndroid Build Coastguard Worker *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
484*0e209d39SAndroid Build Coastguard Worker return 0;
485*0e209d39SAndroid Build Coastguard Worker }
486*0e209d39SAndroid Build Coastguard Worker
487*0e209d39SAndroid Build Coastguard Worker int32_t length = (int32_t)sizeof(UCPTrieHeader) + trie->indexLength * 2;
488*0e209d39SAndroid Build Coastguard Worker switch (valueWidth) {
489*0e209d39SAndroid Build Coastguard Worker case UCPTRIE_VALUE_BITS_16:
490*0e209d39SAndroid Build Coastguard Worker length += trie->dataLength * 2;
491*0e209d39SAndroid Build Coastguard Worker break;
492*0e209d39SAndroid Build Coastguard Worker case UCPTRIE_VALUE_BITS_32:
493*0e209d39SAndroid Build Coastguard Worker length += trie->dataLength * 4;
494*0e209d39SAndroid Build Coastguard Worker break;
495*0e209d39SAndroid Build Coastguard Worker case UCPTRIE_VALUE_BITS_8:
496*0e209d39SAndroid Build Coastguard Worker length += trie->dataLength;
497*0e209d39SAndroid Build Coastguard Worker break;
498*0e209d39SAndroid Build Coastguard Worker default:
499*0e209d39SAndroid Build Coastguard Worker // unreachable
500*0e209d39SAndroid Build Coastguard Worker break;
501*0e209d39SAndroid Build Coastguard Worker }
502*0e209d39SAndroid Build Coastguard Worker if (capacity < length) {
503*0e209d39SAndroid Build Coastguard Worker *pErrorCode = U_BUFFER_OVERFLOW_ERROR;
504*0e209d39SAndroid Build Coastguard Worker return length;
505*0e209d39SAndroid Build Coastguard Worker }
506*0e209d39SAndroid Build Coastguard Worker
507*0e209d39SAndroid Build Coastguard Worker char *bytes = (char *)data;
508*0e209d39SAndroid Build Coastguard Worker UCPTrieHeader *header = (UCPTrieHeader *)bytes;
509*0e209d39SAndroid Build Coastguard Worker header->signature = UCPTRIE_SIG; // "Tri3"
510*0e209d39SAndroid Build Coastguard Worker header->options = (uint16_t)(
511*0e209d39SAndroid Build Coastguard Worker ((trie->dataLength & 0xf0000) >> 4) |
512*0e209d39SAndroid Build Coastguard Worker ((trie->dataNullOffset & 0xf0000) >> 8) |
513*0e209d39SAndroid Build Coastguard Worker (trie->type << 6) |
514*0e209d39SAndroid Build Coastguard Worker valueWidth);
515*0e209d39SAndroid Build Coastguard Worker header->indexLength = (uint16_t)trie->indexLength;
516*0e209d39SAndroid Build Coastguard Worker header->dataLength = (uint16_t)trie->dataLength;
517*0e209d39SAndroid Build Coastguard Worker header->index3NullOffset = trie->index3NullOffset;
518*0e209d39SAndroid Build Coastguard Worker header->dataNullOffset = (uint16_t)trie->dataNullOffset;
519*0e209d39SAndroid Build Coastguard Worker header->shiftedHighStart = trie->highStart >> UCPTRIE_SHIFT_2;
520*0e209d39SAndroid Build Coastguard Worker bytes += sizeof(UCPTrieHeader);
521*0e209d39SAndroid Build Coastguard Worker
522*0e209d39SAndroid Build Coastguard Worker uprv_memcpy(bytes, trie->index, trie->indexLength * 2);
523*0e209d39SAndroid Build Coastguard Worker bytes += trie->indexLength * 2;
524*0e209d39SAndroid Build Coastguard Worker
525*0e209d39SAndroid Build Coastguard Worker switch (valueWidth) {
526*0e209d39SAndroid Build Coastguard Worker case UCPTRIE_VALUE_BITS_16:
527*0e209d39SAndroid Build Coastguard Worker uprv_memcpy(bytes, trie->data.ptr16, trie->dataLength * 2);
528*0e209d39SAndroid Build Coastguard Worker break;
529*0e209d39SAndroid Build Coastguard Worker case UCPTRIE_VALUE_BITS_32:
530*0e209d39SAndroid Build Coastguard Worker uprv_memcpy(bytes, trie->data.ptr32, trie->dataLength * 4);
531*0e209d39SAndroid Build Coastguard Worker break;
532*0e209d39SAndroid Build Coastguard Worker case UCPTRIE_VALUE_BITS_8:
533*0e209d39SAndroid Build Coastguard Worker uprv_memcpy(bytes, trie->data.ptr8, trie->dataLength);
534*0e209d39SAndroid Build Coastguard Worker break;
535*0e209d39SAndroid Build Coastguard Worker default:
536*0e209d39SAndroid Build Coastguard Worker // unreachable
537*0e209d39SAndroid Build Coastguard Worker break;
538*0e209d39SAndroid Build Coastguard Worker }
539*0e209d39SAndroid Build Coastguard Worker return length;
540*0e209d39SAndroid Build Coastguard Worker }
541*0e209d39SAndroid Build Coastguard Worker
542*0e209d39SAndroid Build Coastguard Worker namespace {
543*0e209d39SAndroid Build Coastguard Worker
544*0e209d39SAndroid Build Coastguard Worker #ifdef UCPTRIE_DEBUG
countNull(const UCPTrie * trie)545*0e209d39SAndroid Build Coastguard Worker long countNull(const UCPTrie *trie) {
546*0e209d39SAndroid Build Coastguard Worker uint32_t nullValue=trie->nullValue;
547*0e209d39SAndroid Build Coastguard Worker int32_t length=trie->dataLength;
548*0e209d39SAndroid Build Coastguard Worker long count=0;
549*0e209d39SAndroid Build Coastguard Worker switch (trie->valueWidth) {
550*0e209d39SAndroid Build Coastguard Worker case UCPTRIE_VALUE_BITS_16:
551*0e209d39SAndroid Build Coastguard Worker for(int32_t i=0; i<length; ++i) {
552*0e209d39SAndroid Build Coastguard Worker if(trie->data.ptr16[i]==nullValue) { ++count; }
553*0e209d39SAndroid Build Coastguard Worker }
554*0e209d39SAndroid Build Coastguard Worker break;
555*0e209d39SAndroid Build Coastguard Worker case UCPTRIE_VALUE_BITS_32:
556*0e209d39SAndroid Build Coastguard Worker for(int32_t i=0; i<length; ++i) {
557*0e209d39SAndroid Build Coastguard Worker if(trie->data.ptr32[i]==nullValue) { ++count; }
558*0e209d39SAndroid Build Coastguard Worker }
559*0e209d39SAndroid Build Coastguard Worker break;
560*0e209d39SAndroid Build Coastguard Worker case UCPTRIE_VALUE_BITS_8:
561*0e209d39SAndroid Build Coastguard Worker for(int32_t i=0; i<length; ++i) {
562*0e209d39SAndroid Build Coastguard Worker if(trie->data.ptr8[i]==nullValue) { ++count; }
563*0e209d39SAndroid Build Coastguard Worker }
564*0e209d39SAndroid Build Coastguard Worker break;
565*0e209d39SAndroid Build Coastguard Worker default:
566*0e209d39SAndroid Build Coastguard Worker // unreachable
567*0e209d39SAndroid Build Coastguard Worker break;
568*0e209d39SAndroid Build Coastguard Worker }
569*0e209d39SAndroid Build Coastguard Worker return count;
570*0e209d39SAndroid Build Coastguard Worker }
571*0e209d39SAndroid Build Coastguard Worker
572*0e209d39SAndroid Build Coastguard Worker U_CFUNC void
ucptrie_printLengths(const UCPTrie * trie,const char * which)573*0e209d39SAndroid Build Coastguard Worker ucptrie_printLengths(const UCPTrie *trie, const char *which) {
574*0e209d39SAndroid Build Coastguard Worker long indexLength=trie->indexLength;
575*0e209d39SAndroid Build Coastguard Worker long dataLength=(long)trie->dataLength;
576*0e209d39SAndroid Build Coastguard Worker long totalLength=(long)sizeof(UCPTrieHeader)+indexLength*2+
577*0e209d39SAndroid Build Coastguard Worker dataLength*(trie->valueWidth==UCPTRIE_VALUE_BITS_16 ? 2 :
578*0e209d39SAndroid Build Coastguard Worker trie->valueWidth==UCPTRIE_VALUE_BITS_32 ? 4 : 1);
579*0e209d39SAndroid Build Coastguard Worker printf("**UCPTrieLengths(%s %s)** index:%6ld data:%6ld countNull:%6ld serialized:%6ld\n",
580*0e209d39SAndroid Build Coastguard Worker which, trie->name, indexLength, dataLength, countNull(trie), totalLength);
581*0e209d39SAndroid Build Coastguard Worker }
582*0e209d39SAndroid Build Coastguard Worker #endif
583*0e209d39SAndroid Build Coastguard Worker
584*0e209d39SAndroid Build Coastguard Worker } // namespace
585*0e209d39SAndroid Build Coastguard Worker
586*0e209d39SAndroid Build Coastguard Worker // UCPMap ----
587*0e209d39SAndroid Build Coastguard Worker // Initially, this is the same as UCPTrie. This may well change.
588*0e209d39SAndroid Build Coastguard Worker
589*0e209d39SAndroid Build Coastguard Worker U_CAPI uint32_t U_EXPORT2
ucpmap_get(const UCPMap * map,UChar32 c)590*0e209d39SAndroid Build Coastguard Worker ucpmap_get(const UCPMap *map, UChar32 c) {
591*0e209d39SAndroid Build Coastguard Worker return ucptrie_get(reinterpret_cast<const UCPTrie *>(map), c);
592*0e209d39SAndroid Build Coastguard Worker }
593*0e209d39SAndroid Build Coastguard Worker
594*0e209d39SAndroid Build Coastguard Worker U_CAPI UChar32 U_EXPORT2
ucpmap_getRange(const UCPMap * map,UChar32 start,UCPMapRangeOption option,uint32_t surrogateValue,UCPMapValueFilter * filter,const void * context,uint32_t * pValue)595*0e209d39SAndroid Build Coastguard Worker ucpmap_getRange(const UCPMap *map, UChar32 start,
596*0e209d39SAndroid Build Coastguard Worker UCPMapRangeOption option, uint32_t surrogateValue,
597*0e209d39SAndroid Build Coastguard Worker UCPMapValueFilter *filter, const void *context, uint32_t *pValue) {
598*0e209d39SAndroid Build Coastguard Worker return ucptrie_getRange(reinterpret_cast<const UCPTrie *>(map), start,
599*0e209d39SAndroid Build Coastguard Worker option, surrogateValue,
600*0e209d39SAndroid Build Coastguard Worker filter, context, pValue);
601*0e209d39SAndroid Build Coastguard Worker }
602