Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #ifndef nsCharTraits_h___
8 : #define nsCharTraits_h___
9 :
10 : #include <ctype.h> // for |EOF|, |WEOF|
11 : #include <string.h> // for |memcpy|, et al
12 :
13 : #include "nscore.h" // for |char16_t|
14 :
15 : // This file may be used (through nsUTF8Utils.h) from non-XPCOM code, in
16 : // particular the standalone software updater. In that case stub out
17 : // the macros provided by nsDebug.h which are only usable when linking XPCOM
18 :
19 : #ifdef NS_NO_XPCOM
20 : #define NS_WARNING(msg)
21 : #define NS_ASSERTION(cond, msg)
22 : #define NS_ERROR(msg)
23 : #else
24 : #include "nsDebug.h" // for NS_ASSERTION
25 : #endif
26 :
27 : /*
28 : * Some macros for converting char16_t (UTF-16) to and from Unicode scalar
29 : * values.
30 : *
31 : * Note that UTF-16 represents all Unicode scalar values up to U+10FFFF by
32 : * using "surrogate pairs". These consist of a high surrogate, i.e. a code
33 : * point in the range U+D800 - U+DBFF, and a low surrogate, i.e. a code point
34 : * in the range U+DC00 - U+DFFF, like this:
35 : *
36 : * U+D800 U+DC00 = U+10000
37 : * U+D800 U+DC01 = U+10001
38 : * ...
39 : * U+DBFF U+DFFE = U+10FFFE
40 : * U+DBFF U+DFFF = U+10FFFF
41 : *
42 : * These surrogate code points U+D800 - U+DFFF are not themselves valid Unicode
43 : * scalar values and are not well-formed UTF-16 except as high-surrogate /
44 : * low-surrogate pairs.
45 : */
46 :
47 : #define PLANE1_BASE uint32_t(0x00010000)
48 : // High surrogates are in the range 0xD800 -- OxDBFF
49 : #define NS_IS_HIGH_SURROGATE(u) ((uint32_t(u) & 0xFFFFFC00) == 0xD800)
50 : // Low surrogates are in the range 0xDC00 -- 0xDFFF
51 : #define NS_IS_LOW_SURROGATE(u) ((uint32_t(u) & 0xFFFFFC00) == 0xDC00)
52 : // Faster than testing NS_IS_HIGH_SURROGATE || NS_IS_LOW_SURROGATE
53 : #define IS_SURROGATE(u) ((uint32_t(u) & 0xFFFFF800) == 0xD800)
54 :
55 : // Everything else is not a surrogate: 0x000 -- 0xD7FF, 0xE000 -- 0xFFFF
56 :
57 : // N = (H - 0xD800) * 0x400 + 0x10000 + (L - 0xDC00)
58 : // I wonder whether we could somehow assert that H is a high surrogate
59 : // and L is a low surrogate
60 : #define SURROGATE_TO_UCS4(h, l) (((uint32_t(h) & 0x03FF) << 10) + \
61 : (uint32_t(l) & 0x03FF) + PLANE1_BASE)
62 :
63 : // Extract surrogates from a UCS4 char
64 : // Reference: the Unicode standard 4.0, section 3.9
65 : // Since (c - 0x10000) >> 10 == (c >> 10) - 0x0080 and
66 : // 0xD7C0 == 0xD800 - 0x0080,
67 : // ((c - 0x10000) >> 10) + 0xD800 can be simplified to
68 : #define H_SURROGATE(c) char16_t(char16_t(uint32_t(c) >> 10) + \
69 : char16_t(0xD7C0))
70 : // where it's to be noted that 0xD7C0 is not bitwise-OR'd
71 : // but added.
72 :
73 : // Since 0x10000 & 0x03FF == 0,
74 : // (c - 0x10000) & 0x03FF == c & 0x03FF so that
75 : // ((c - 0x10000) & 0x03FF) | 0xDC00 is equivalent to
76 : #define L_SURROGATE(c) char16_t(char16_t(uint32_t(c) & uint32_t(0x03FF)) | \
77 : char16_t(0xDC00))
78 :
79 : #define IS_IN_BMP(ucs) (uint32_t(ucs) < PLANE1_BASE)
80 : #define UCS2_REPLACEMENT_CHAR char16_t(0xFFFD)
81 :
82 : #define UCS_END uint32_t(0x00110000)
83 : #define IS_VALID_CHAR(c) ((uint32_t(c) < UCS_END) && !IS_SURROGATE(c))
84 : #define ENSURE_VALID_CHAR(c) (IS_VALID_CHAR(c) ? (c) : UCS2_REPLACEMENT_CHAR)
85 :
86 : template <class CharT>
87 : struct nsCharTraits
88 : {
89 : };
90 :
91 : template <>
92 : struct nsCharTraits<char16_t>
93 : {
94 : typedef char16_t char_type;
95 : typedef uint16_t unsigned_char_type;
96 : typedef char incompatible_char_type;
97 :
98 : static char_type* const sEmptyBuffer;
99 :
100 : // integer representation of characters:
101 : typedef int int_type;
102 :
103 : static char_type
104 : to_char_type(int_type aChar)
105 : {
106 : return char_type(aChar);
107 : }
108 :
109 : static int_type
110 195934 : to_int_type(char_type aChar)
111 : {
112 195934 : return int_type(static_cast<unsigned_char_type>(aChar));
113 : }
114 :
115 : static bool
116 6835 : eq_int_type(int_type aLhs, int_type aRhs)
117 : {
118 6835 : return aLhs == aRhs;
119 : }
120 :
121 :
122 : // |char_type| comparisons:
123 :
124 : static bool
125 427978 : eq(char_type aLhs, char_type aRhs)
126 : {
127 427978 : return aLhs == aRhs;
128 : }
129 :
130 : static bool
131 : lt(char_type aLhs, char_type aRhs)
132 : {
133 : return aLhs < aRhs;
134 : }
135 :
136 :
137 : // operations on s[n] arrays:
138 :
139 : static char_type*
140 7012 : move(char_type* aStr1, const char_type* aStr2, size_t aN)
141 : {
142 7012 : return static_cast<char_type*>(memmove(aStr1, aStr2,
143 7012 : aN * sizeof(char_type)));
144 : }
145 :
146 : static char_type*
147 81370 : copy(char_type* aStr1, const char_type* aStr2, size_t aN)
148 : {
149 81370 : return static_cast<char_type*>(memcpy(aStr1, aStr2,
150 81370 : aN * sizeof(char_type)));
151 : }
152 :
153 : static char_type*
154 1853 : copyASCII(char_type* aStr1, const char* aStr2, size_t aN)
155 : {
156 17578 : for (char_type* s = aStr1; aN--; ++s, ++aStr2) {
157 15725 : NS_ASSERTION(!(*aStr2 & ~0x7F), "Unexpected non-ASCII character");
158 15725 : *s = static_cast<char_type>(*aStr2);
159 : }
160 1853 : return aStr1;
161 : }
162 :
163 : static int
164 333803 : compare(const char_type* aStr1, const char_type* aStr2, size_t aN)
165 : {
166 634166 : for (; aN--; ++aStr1, ++aStr2) {
167 315690 : if (!eq(*aStr1, *aStr2)) {
168 15327 : return to_int_type(*aStr1) - to_int_type(*aStr2);
169 : }
170 : }
171 :
172 18113 : return 0;
173 : }
174 :
175 : static int
176 8443 : compareASCII(const char_type* aStr1, const char* aStr2, size_t aN)
177 : {
178 14684 : for (; aN--; ++aStr1, ++aStr2) {
179 6423 : NS_ASSERTION(!(*aStr2 & ~0x7F), "Unexpected non-ASCII character");
180 6423 : if (!eq_int_type(to_int_type(*aStr1),
181 6423 : to_int_type(static_cast<char_type>(*aStr2)))) {
182 182 : return to_int_type(*aStr1) -
183 182 : to_int_type(static_cast<char_type>(*aStr2));
184 : }
185 : }
186 :
187 2020 : return 0;
188 : }
189 :
190 : // this version assumes that s2 is null-terminated and s1 has length n.
191 : // if s1 is shorter than s2 then we return -1; if s1 is longer than s2,
192 : // we return 1.
193 : static int
194 444 : compareASCIINullTerminated(const char_type* aStr1, size_t aN,
195 : const char* aStr2)
196 : {
197 785 : for (; aN--; ++aStr1, ++aStr2) {
198 412 : if (!*aStr2) {
199 0 : return 1;
200 : }
201 412 : NS_ASSERTION(!(*aStr2 & ~0x7F), "Unexpected non-ASCII character");
202 412 : if (!eq_int_type(to_int_type(*aStr1),
203 412 : to_int_type(static_cast<char_type>(*aStr2)))) {
204 71 : return to_int_type(*aStr1) -
205 71 : to_int_type(static_cast<char_type>(*aStr2));
206 : }
207 : }
208 :
209 32 : if (*aStr2) {
210 8 : return -1;
211 : }
212 :
213 24 : return 0;
214 : }
215 :
216 : /**
217 : * Convert c to its lower-case form, but only if c is in the ASCII
218 : * range. Otherwise leave it alone.
219 : */
220 : static char_type
221 233637 : ASCIIToLower(char_type aChar)
222 : {
223 233637 : if (aChar >= 'A' && aChar <= 'Z') {
224 1299 : return char_type(aChar + ('a' - 'A'));
225 : }
226 :
227 232338 : return aChar;
228 : }
229 :
230 : static int
231 177087 : compareLowerCaseToASCII(const char_type* aStr1, const char* aStr2, size_t aN)
232 : {
233 327393 : for (; aN--; ++aStr1, ++aStr2) {
234 155980 : NS_ASSERTION(!(*aStr2 & ~0x7F), "Unexpected non-ASCII character");
235 155980 : NS_ASSERTION(!(*aStr2 >= 'A' && *aStr2 <= 'Z'),
236 : "Unexpected uppercase character");
237 155980 : char_type lower_s1 = ASCIIToLower(*aStr1);
238 155980 : if (lower_s1 != static_cast<char_type>(*aStr2)) {
239 5674 : return to_int_type(lower_s1) -
240 5674 : to_int_type(static_cast<char_type>(*aStr2));
241 : }
242 : }
243 :
244 21107 : return 0;
245 : }
246 :
247 : // this version assumes that s2 is null-terminated and s1 has length n.
248 : // if s1 is shorter than s2 then we return -1; if s1 is longer than s2,
249 : // we return 1.
250 : static int
251 78250 : compareLowerCaseToASCIINullTerminated(const char_type* aStr1,
252 : size_t aN, const char* aStr2)
253 : {
254 86029 : for (; aN--; ++aStr1, ++aStr2) {
255 77666 : if (!*aStr2) {
256 9 : return 1;
257 : }
258 77657 : NS_ASSERTION(!(*aStr2 & ~0x7F), "Unexpected non-ASCII character");
259 77657 : NS_ASSERTION(!(*aStr2 >= 'A' && *aStr2 <= 'Z'),
260 : "Unexpected uppercase character");
261 77657 : char_type lower_s1 = ASCIIToLower(*aStr1);
262 77657 : if (lower_s1 != static_cast<char_type>(*aStr2)) {
263 69878 : return to_int_type(lower_s1) -
264 69878 : to_int_type(static_cast<char_type>(*aStr2));
265 : }
266 : }
267 :
268 584 : if (*aStr2) {
269 36 : return -1;
270 : }
271 :
272 548 : return 0;
273 : }
274 :
275 : static size_t
276 7591 : length(const char_type* aStr)
277 : {
278 7591 : size_t result = 0;
279 210069 : while (!eq(*aStr++, char_type(0))) {
280 101239 : ++result;
281 : }
282 7591 : return result;
283 : }
284 :
285 : static const char_type*
286 3617 : find(const char_type* aStr, size_t aN, char_type aChar)
287 : {
288 6929 : while (aN--) {
289 3458 : if (eq(*aStr, aChar)) {
290 146 : return aStr;
291 : }
292 3312 : ++aStr;
293 : }
294 :
295 159 : return 0;
296 : }
297 : };
298 :
299 : template <>
300 : struct nsCharTraits<char>
301 : {
302 : typedef char char_type;
303 : typedef unsigned char unsigned_char_type;
304 : typedef char16_t incompatible_char_type;
305 :
306 : static char_type* const sEmptyBuffer;
307 :
308 : // integer representation of characters:
309 :
310 : typedef int int_type;
311 :
312 : static char_type
313 : to_char_type(int_type aChar)
314 : {
315 : return char_type(aChar);
316 : }
317 :
318 : static int_type
319 19881 : to_int_type(char_type aChar)
320 : {
321 19881 : return int_type(static_cast<unsigned_char_type>(aChar));
322 : }
323 :
324 : static bool
325 : eq_int_type(int_type aLhs, int_type aRhs)
326 : {
327 : return aLhs == aRhs;
328 : }
329 :
330 :
331 : // |char_type| comparisons:
332 :
333 : static bool eq(char_type aLhs, char_type aRhs)
334 : {
335 : return aLhs == aRhs;
336 : }
337 :
338 : static bool
339 : lt(char_type aLhs, char_type aRhs)
340 : {
341 : return aLhs < aRhs;
342 : }
343 :
344 :
345 : // operations on s[n] arrays:
346 :
347 : static char_type*
348 4863 : move(char_type* aStr1, const char_type* aStr2, size_t aN)
349 : {
350 : return static_cast<char_type*>(memmove(aStr1, aStr2,
351 4863 : aN * sizeof(char_type)));
352 : }
353 :
354 : static char_type*
355 149055 : copy(char_type* aStr1, const char_type* aStr2, size_t aN)
356 : {
357 : return static_cast<char_type*>(memcpy(aStr1, aStr2,
358 149055 : aN * sizeof(char_type)));
359 : }
360 :
361 : static char_type*
362 6453 : copyASCII(char_type* aStr1, const char* aStr2, size_t aN)
363 : {
364 6453 : return copy(aStr1, aStr2, aN);
365 : }
366 :
367 : static int
368 285140 : compare(const char_type* aStr1, const char_type* aStr2, size_t aN)
369 : {
370 285140 : return memcmp(aStr1, aStr2, aN);
371 : }
372 :
373 : static int
374 10523 : compareASCII(const char_type* aStr1, const char* aStr2, size_t aN)
375 : {
376 : #ifdef DEBUG
377 48523 : for (size_t i = 0; i < aN; ++i) {
378 38000 : NS_ASSERTION(!(aStr2[i] & ~0x7F), "Unexpected non-ASCII character");
379 : }
380 : #endif
381 10523 : return compare(aStr1, aStr2, aN);
382 : }
383 :
384 : // this version assumes that s2 is null-terminated and s1 has length n.
385 : // if s1 is shorter than s2 then we return -1; if s1 is longer than s2,
386 : // we return 1.
387 : static int
388 418 : compareASCIINullTerminated(const char_type* aStr1, size_t aN,
389 : const char* aStr2)
390 : {
391 : // can't use strcmp here because we don't want to stop when aStr1
392 : // contains a null
393 823 : for (; aN--; ++aStr1, ++aStr2) {
394 405 : if (!*aStr2) {
395 0 : return 1;
396 : }
397 405 : NS_ASSERTION(!(*aStr2 & ~0x7F), "Unexpected non-ASCII character");
398 405 : if (*aStr1 != *aStr2) {
399 0 : return to_int_type(*aStr1) - to_int_type(*aStr2);
400 : }
401 : }
402 :
403 13 : if (*aStr2) {
404 0 : return -1;
405 : }
406 :
407 13 : return 0;
408 : }
409 :
410 : /**
411 : * Convert c to its lower-case form, but only if c is ASCII.
412 : */
413 : static char_type
414 20237 : ASCIIToLower(char_type aChar)
415 : {
416 20237 : if (aChar >= 'A' && aChar <= 'Z') {
417 0 : return char_type(aChar + ('a' - 'A'));
418 : }
419 :
420 20237 : return aChar;
421 : }
422 :
423 : static int
424 22297 : compareLowerCaseToASCII(const char_type* aStr1, const char* aStr2, size_t aN)
425 : {
426 36965 : for (; aN--; ++aStr1, ++aStr2) {
427 18647 : NS_ASSERTION(!(*aStr2 & ~0x7F), "Unexpected non-ASCII character");
428 18647 : NS_ASSERTION(!(*aStr2 >= 'A' && *aStr2 <= 'Z'),
429 : "Unexpected uppercase character");
430 18647 : char_type lower_s1 = ASCIIToLower(*aStr1);
431 18647 : if (lower_s1 != *aStr2) {
432 3979 : return to_int_type(lower_s1) - to_int_type(*aStr2);
433 : }
434 : }
435 3650 : return 0;
436 : }
437 :
438 : // this version assumes that s2 is null-terminated and s1 has length n.
439 : // if s1 is shorter than s2 then we return -1; if s1 is longer than s2,
440 : // we return 1.
441 : static int
442 1749 : compareLowerCaseToASCIINullTerminated(const char_type* aStr1, size_t aN,
443 : const char* aStr2)
444 : {
445 2295 : for (; aN--; ++aStr1, ++aStr2) {
446 1595 : if (!*aStr2) {
447 5 : return 1;
448 : }
449 1590 : NS_ASSERTION(!(*aStr2 & ~0x7F), "Unexpected non-ASCII character");
450 1590 : NS_ASSERTION(!(*aStr2 >= 'A' && *aStr2 <= 'Z'),
451 : "Unexpected uppercase character");
452 1590 : char_type lower_s1 = ASCIIToLower(*aStr1);
453 1590 : if (lower_s1 != *aStr2) {
454 1044 : return to_int_type(lower_s1) - to_int_type(*aStr2);
455 : }
456 : }
457 :
458 154 : if (*aStr2) {
459 28 : return -1;
460 : }
461 :
462 126 : return 0;
463 : }
464 :
465 : static size_t
466 118467 : length(const char_type* aStr)
467 : {
468 118467 : return strlen(aStr);
469 : }
470 :
471 : static const char_type*
472 9835 : find(const char_type* aStr, size_t aN, char_type aChar)
473 : {
474 9835 : return reinterpret_cast<const char_type*>(memchr(aStr, to_int_type(aChar),
475 9835 : aN));
476 : }
477 : };
478 :
479 : template <class InputIterator>
480 : struct nsCharSourceTraits
481 : {
482 : typedef typename InputIterator::difference_type difference_type;
483 :
484 : static uint32_t
485 31724 : readable_distance(const InputIterator& aFirst, const InputIterator& aLast)
486 : {
487 : // assumes single fragment
488 31724 : return uint32_t(aLast.get() - aFirst.get());
489 : }
490 :
491 : static const typename InputIterator::value_type*
492 31724 : read(const InputIterator& aIter)
493 : {
494 31724 : return aIter.get();
495 : }
496 :
497 : static void
498 : advance(InputIterator& aStr, difference_type aN)
499 : {
500 : aStr.advance(aN);
501 : }
502 : };
503 :
504 : template <class CharT>
505 : struct nsCharSourceTraits<CharT*>
506 : {
507 : typedef ptrdiff_t difference_type;
508 :
509 : static uint32_t
510 : readable_distance(CharT* aStr)
511 : {
512 : return uint32_t(nsCharTraits<CharT>::length(aStr));
513 : // return numeric_limits<uint32_t>::max();
514 : }
515 :
516 : static uint32_t
517 172 : readable_distance(CharT* aFirst, CharT* aLast)
518 : {
519 172 : return uint32_t(aLast - aFirst);
520 : }
521 :
522 : static const CharT*
523 172 : read(CharT* aStr)
524 : {
525 172 : return aStr;
526 : }
527 :
528 : static void
529 : advance(CharT*& aStr, difference_type aN)
530 : {
531 : aStr += aN;
532 : }
533 : };
534 :
535 : template <class OutputIterator>
536 : struct nsCharSinkTraits
537 : {
538 : static void
539 20978 : write(OutputIterator& aIter, const typename OutputIterator::value_type* aStr,
540 : uint32_t aN)
541 : {
542 20978 : aIter.write(aStr, aN);
543 20978 : }
544 : };
545 :
546 : template <class CharT>
547 : struct nsCharSinkTraits<CharT*>
548 : {
549 : static void
550 10918 : write(CharT*& aIter, const CharT* aStr, uint32_t aN)
551 : {
552 10918 : nsCharTraits<CharT>::move(aIter, aStr, aN);
553 10918 : aIter += aN;
554 10918 : }
555 : };
556 :
557 : #endif // !defined(nsCharTraits_h___)
|