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