Coverage Report

Created: 2026-03-31 06:12

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