Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
collate.cpp
Go to the documentation of this file.
1
29#define _RWSTD_LIB_SRC
30
31#if 3 == __GNUG__ && 3 > __GNUC_MINOR__ \
32 || 3 == __GNUC_MINOR__ && 1 >__GNUC_PATCHLEVEL__
33
34 // working around a gcc bug (PR #29570)
35# include <rw/_config.h>
36# ifndef _RWSTD_NO_EXTERN_TEMPLATE
37# define _RWSTD_NO_EXTERN_TEMPLATE
38# endif
39#endif // gcc >= 3.0 && gcc < 3.3.1
40
41#include <rw/_defs.h>
42
43#include <limits> // for numeric_limits
44
45#include <limits.h>
46#include <stdlib.h> // for wcstombs()
47#include <string.h> // for memchr(), memcpy()
48
49#ifndef _RWSTD_NO_WCHAR_H
50# include <wchar.h> // for wcscoll(), wcsxfrm(), wmemcmp()
51#endif // _RWSTD_NO_WCHAR_H
52
53#include <loc/_collate.h>
54#include <loc/_locale.h>
55#include <loc/_localedef.h>
56
57#include "locale_body.h"
58#include "podarray.h" // for __rw_pod_array
59#include "setlocale.h" // for __rw_setlocale
60
61// define _RWSTD_MB_MAX to the greater of MB_LEN_MAX and 8
62// where 8 the maximum length necessary to encode a Unicode
63// character in UTF-8
64#if _RWSTD_MB_LEN_MAX < 8
65# define _RWSTD_MB_MAX 8
66#else
67# define _RWSTD_MB_MAX _RWSTD_MB_LEN_MAX
68#endif // _RWSTD_MB_LEN_MAX
69
70
71#if defined (_RWSTD_NO_WCSCOLL) && !defined (_RWSTD_NO_WCSCOLL_IN_LIBC)
72
73extern "C" {
74
75// declare if not declared in the system header(s)
76int wcscoll (const wchar_t*, const wchar_t*) _LIBC_THROWS ();
77
78# undef _RWSTD_NO_WCSCOLL
79
80} // extern "C"
81
82#endif // _RWSTD_NO_WCSCOLL && !_RWSTD_NO_WCSCOLL_IN_LIBC
83
84
85#ifdef _RWSTD_NO_WCSXFRM
86# ifndef _RWSTD_NO_WCSXFRM_IN_LIBC
87
88extern "C" {
89
90// declare if not declared in the system header(s)
91_RWSTD_SIZE_T wcsxfrm (wchar_t*, const wchar_t*, _RWSTD_SIZE_T) _LIBC_THROWS ();
92
93# define _RWSTD_WCSXFRM wcsxfrm
94# undef _RWSTD_NO_WCSXFRM
95
96} // extern "C"
97
98# else
99# define _RWSTD_WCSXFRM _RW::__rw_wcsxfrm
100# endif // _RWSTD_NO_WCSXFRM_IN_LIBC
101#else
102# define _RWSTD_WCSXFRM wcsxfrm
103#endif // _RWSTD_NO_WCSXFRM
104
105
106#if defined (_RWSTD_NO_WCSTOMBS) && !defined (_RWSTD_NO_WCSTOMBS_IN_LIBC)
107
108extern "C" {
109
110// declare if not declared in the system header(s)
111_RWSTD_DLLIMPORT _RWSTD_SIZE_T
112wcstombs (char*, const wchar_t*, _RWSTD_SIZE_T) _LIBC_THROWS ();
113
114# undef _RWSTD_NO_WCSTOMBS
115
116} // extern "C"
117
118#endif // _RWSTD_NO_WCSTOMBS && !_RWSTD_NO_WCSTOMBS_IN_LIBC
119
120
121// for convenience
122typedef unsigned char UChar;
123
124
126
127#undef min
128#undef max
129
130
131// computes LC_XXX category from a numeric facet id, returns the
132// LC_XXX category for standard facets, LC_ALL for all others
133int __rw_get_cat (int);
134
135
136#ifndef _RWSTD_NO_WCHAR_T
137
138_RWSTD_INTERNAL void
139__rw_append_weight (const _RW::__rw_collate_t *impl,
140 const unsigned *weights,
141 _STD::wstring &out)
142{
143 // append the weight(s) to the out string
144 for (int i = 0; i < impl->longest_weight; ++i, ++weights) {
145
146 const unsigned int wt = *weights;
147
148 // if the weight is not an IGNORE weight
149 // then add it to the out string
150 if (wt && wt != _RWSTD_UINT_MAX) {
151 out += wchar_t (wt);
152 }
153
154 }
155}
156
157#endif // _RWSTD_NO_WCHAR_T
158
159
160_RWSTD_INTERNAL void
161__rw_append_weight (const _RW::__rw_collate_t *impl,
162 const unsigned int *weights,
163 _STD::string &out)
164{
165 // append the weight(s) to the out string
166 for (int i = 0; i < impl->longest_weight; ++i, ++weights) {
167
168 unsigned wt = *weights;
169
170 // if the weight is not an IGNORE weight
171 // then add it to the out string
172
173 if (wt && wt != _RWSTD_UINT_MAX) {
174
175 while (_RWSTD_CHAR_MAX < wt) {
176 out += char (_RWSTD_CHAR_MAX);
177 wt -= _RWSTD_CHAR_MAX;
178 }
179
180 // the weight will fit a signed char
181 // so add it to the out str
182 out += char (wt);
183 }
184 }
185}
186
187
188template <class _STR_T>
189static void
190__rw_process_offsets (_RW::__rw_collate_t *impl,
191 const unsigned **start,
192 const unsigned **end,
193 _STR_T &out)
194{
195
196 // process the offset list for each pass.
197
198 for (unsigned int pass = 0; pass < impl->num_weights; pass++) {
199 // first get the order for the start element in this pass
200 unsigned int shift_value = (impl->num_weights - (pass + 1)) * 2;
201
202 const unsigned int** cur_start = start;
203 const unsigned int** cur_end = start;
204
205 if (*cur_start == *end)
206 return;
207
208 do {
209 // calculate the order from the bitmask order in front of each
210 // character's weight information. Each character may have
211 // different orderings although most likely there will be groups
212 // of characters with the same ordering.
213 unsigned int cur_ord = (**cur_end >> shift_value) & 0x00000003;
214 while (cur_end != end && ((**cur_end >> shift_value)
215 & 0x00000003) == cur_ord) {
216 cur_end++;
217 }
218
219 const unsigned int** cur;
220 switch (cur_ord) {
221 case 0:
222 // forward weight type
223 for (cur = cur_start; cur < cur_end; cur++) {
224 const unsigned int* weightp = *cur;
225 weightp = weightp + 1 + pass * impl->longest_weight;
226
227 // qualify the call to make sure the function
228 // is found during lookup when declared static
229 _RW::__rw_append_weight (impl, weightp, out);
230 }
231 break;
232
233 case 1:
234 // backward weight type
235 for (cur = cur_end - 1; cur >= cur_start; cur --) {
236 const unsigned int* weightp = *cur;
237 weightp = weightp + 1 + pass * impl->longest_weight;
238
239 // qualify the call to make sure the function
240 // is found during lookup when declared static
241 _RW::__rw_append_weight (impl, weightp, out);
242 }
243 break;
244
245 case 2:
246 // forward,position weight type.
247 // The string with a non-IGNOREd element after the
248 // fewest IGNORED elements should collate first
249 for (cur = cur_start; cur < cur_end; cur++) {
250 const unsigned int* weightp = *cur;
251 weightp = weightp + 1 + pass * impl->longest_weight;
252 // output the CHAR_MAX value for every IGNORE
253 // weight that we see. The first string that has a
254 // non-ignore value will collate first
255
256 if (*weightp == 0) {
257 typedef typename _STR_T::value_type CharT;
258
259 const CharT ign =
260 _STD::numeric_limits<CharT>::max ();
261
262 out += ign;
263 }
264 else {
265 // qualify the call to make sure the function
266 // is found during lookup when declared static
267 _RW::__rw_append_weight (impl, weightp, out);
268 }
269 }
270 break;
271
272 case 3:
273 // backward,position weight type
274 for (cur = cur_end - 1; cur >= cur_start; cur --) {
275 const unsigned int* weightp = *cur;
276 weightp = weightp + 1 + pass * impl->longest_weight;
277 // non-ignore value will collate first
278 if (*weightp == 0) {
279 typedef typename _STR_T::value_type CharT;
280
281 const CharT ign =
282 _STD::numeric_limits<CharT>::max ();
283
284 out += ign;
285 }
286 else
287 // qualify the call to make sure the function
288 // is found during lookup when declared static
289 _RW::__rw_append_weight (impl, weightp, out);
290 }
291 break;
292 }
293
294 // append a 1 to designate the end of the pass
295 typedef typename _STR_T::value_type CharT;
296 out += CharT (1);
297
298 cur_start = cur_end;
299 } while (cur_end != end);
300 }
301}
302
303#ifndef _RWSTD_NO_WCHAR_T
304
305static int
306__rw_get_w_ce_offset (const __rw_collate_t *impl,
307 const wchar_t** cur_char,
308 const wchar_t* end)
309{
310 // obtain the offset of a wide collating element. If no collating
311 // elements can be made with the current position of the string
312 // then return -1
313
314 if (impl->largest_ce > 1) {
315
316 unsigned int cur_tab = 0;
317
318 char utf8_enc [_RWSTD_MB_MAX];
319
320 const unsigned int* tab;
321 while (*cur_char < end) {
322
323 // convert the next wchar_t character to a utf8 encoded character
324 const _RWSTD_SIZE_T nbytes =
325 _RW::__rw_itoutf8 (**cur_char, utf8_enc);
326
327 for (_RWSTD_SIZE_T i = 0; i < nbytes; i++) {
328
329 const unsigned c1 = impl->get_first_char_in_w_ce_tab (cur_tab);
330 const unsigned c2 = impl->get_last_char_in_w_ce_tab (cur_tab);
331
332 if (UChar (utf8_enc [i]) < c1 || UChar (utf8_enc [i]) > c2)
333 return -1;
334
335 tab = impl->get_w_ce_tab (cur_tab);
336
337 const unsigned int next_off = tab [UChar (utf8_enc [i]) - c1];
338 if (next_off == _RWSTD_UINT_MAX) {
339 return -1;
340 }
341
342 if (next_off & 0x80000000) {
343 cur_tab = next_off &~ 0x80000000;
344 continue;
345 }
346
347 return next_off;
348 }
349 (*cur_char)++;
350 }
351 }
352 return -1;
353}
354
355
356static int
357__rw_get_wchar_offset (const __rw_collate_t *impl,
358 const wchar_t** cur_char,
359 const wchar_t* end)
360{
361 // get the offset of the weight information for the current wide character
362
363 unsigned cur_tab = 0;
364 char utf8_enc [_RWSTD_MB_MAX];
365
366 while (*cur_char < end) {
367 // convert the next wchar_t character to a utf8 encoded character
368 const _RWSTD_SIZE_T nbytes =
369 _RW::__rw_itoutf8 (**cur_char, utf8_enc);
370
371 for (_RWSTD_SIZE_T i = 0; i < nbytes; i++) {
372 const unsigned c1 = impl->get_first_char_in_w_tab (cur_tab);
373 if (UChar (utf8_enc [i]) < c1)
374 return -1;
375
376 const unsigned* const tab = impl->get_w_tab (cur_tab);
377
378 const unsigned int next_off = tab [UChar (utf8_enc [i]) - c1];
379 if (next_off == _RWSTD_UINT_MAX) {
380 return -1;
381 }
382
383 if (next_off & 0x80000000) {
384 cur_tab = next_off &~ 0x80000000;
385 continue;
386 }
387
388 return next_off;
389 }
390 (*cur_char)++;
391 }
392 return -1;
393}
394
395#endif // _RWSTD_NO_WCHAR_T
396
397
398static int
399__rw_get_n_ce_offset (const __rw_collate_t *impl,
400 const char **cur_char,
401 const char *end)
402{
403 if (impl->largest_ce > 1) {
404 unsigned int cur_tab = 0;
405 const unsigned int* tab;
406
407 while (*cur_char < end ) {
408 const unsigned c1 = impl->get_first_char_in_n_ce_tab (cur_tab);
409 const unsigned c2 = impl->get_last_char_in_n_ce_tab (cur_tab);
410 if (UChar (**cur_char) < c1 || UChar (**cur_char) > c2)
411 return -1;
412
413 tab = impl->get_n_ce_tab (cur_tab);
414
415 unsigned int next_off = tab [UChar (**cur_char) - c1];
416 if (next_off == _RWSTD_UINT_MAX) {
417 return -1;
418 }
419
420 if (next_off & 0x80000000) {
421 (*cur_char)++;
422 cur_tab = next_off &~ 0x80000000;
423 }
424 else {
425 return next_off;
426 }
427 }
428 }
429 return -1;
430}
431
432
433static int
434__rw_get_char_offset (const __rw_collate_t *impl,
435 const char** cur_char,
436 const char* end)
437{
438 unsigned int cur_tab = 0;
439
440 while (*cur_char < end) {
441 unsigned c1 = impl->get_first_char_in_n_tab (cur_tab);
442 if (UChar (**cur_char) < c1)
443 return -1;
444
445 const unsigned int* tab = impl->get_n_tab (cur_tab);
446 c1 = impl->get_first_char_in_n_tab (cur_tab);
447
448 unsigned int next_off = tab [UChar (**cur_char) - c1];
449 if (next_off == _RWSTD_UINT_MAX) {
450 return -1;
451 }
452
453 if (next_off & 0x80000000) {
454 (*cur_char)++;
455 cur_tab = next_off &~ 0x80000000;
456 }
457 else {
458 return next_off;
459 }
460 }
461
462 return -1;
463}
464
465
466// returns true if the character sequence starting at `from'
467// does not form a valid complete multibyte character
468static inline bool
469__rw_is_invalid (const unsigned int* first_tab, const char *from)
470{
471 return 0 != (__rw_mbtowco (first_tab, from, 0) & 0x80000000);
472}
473
474
475// same as strxfrm() except that it takes the number of characters
476// in an array that may contain embedded NULs; these are inserted
477// into the transformed string
478static _STD::string
479__rw_strnxfrm (const char *src, _RWSTD_SIZE_T nchars)
480{
481 _STD::string res;
482
483 char buf [256];
484 char *pbuf = buf;
485
486 _RWSTD_SIZE_T bufsize = sizeof buf;
487 char *psrc = buf;
488
489 while (nchars) {
490
491 // using a C-style cast instead of static_cast to avoid
492 // a gcc 2.95.2 bug causing an error on some platforms:
493 // static_cast from `void *' to `const char *'
494 const char* const last = (const char*)memchr (src, '\0', nchars);
495
496 if (0 == last) {
497
498 // no NUL found in the initial portion of the source string
499 // that fits into the local temporary buffer; copy as many
500 // characters as fit into the buffer
501
502 if (bufsize <= nchars) {
503 if (pbuf != buf)
504 delete[] pbuf;
505 pbuf = new char [nchars + 1];
506 }
507
508 psrc = pbuf;
509 memcpy (psrc, src, nchars);
510
511 // append a terminating NUL and decrement the number
512 // of characters that remain to be processed
513 psrc [nchars] = '\0';
514 src += nchars;
515 nchars = 0;
516 }
517 else {
518
519 // terminating NUL found in the source buffer
520 nchars -= (last - src) + 1;
521 psrc = _RWSTD_CONST_CAST (char*, src);
522 src += (last - src) + 1;
523 }
524
525 // provide a destination buffer to strxfrm() in case
526 // it's buggy (such as MSVC's) and tries to write to
527 // the buffer even if it's 0
528 char just_in_case_buf [8];
529 const _RWSTD_SIZE_T dst_size = strxfrm (just_in_case_buf, psrc, 0);
530
531 // check for strxfrm() errors
532 if (0 == (dst_size << 1))
533 return _STD::string ();
534
535 _RWSTD_SIZE_T res_size = res.size ();
536
537 _TRY {
538 // resize the result string to fit itself plus the result
539 // of the transformation including the terminatin NUL
540 // appended by strxfrm()
541 res.resize (res_size + dst_size + 1);
542 }
543 _CATCH (...) {
544 if (pbuf != buf)
545 delete[] pbuf;
546 _RETHROW;
547 }
548
549 // transfor the source string up to the terminating NUL
550 _RWSTD_SIZE_T xfrm_size =
551 strxfrm (&res [0] + res_size, psrc, dst_size + 1);
552
553#if defined _MSC_VER && _MSC_VER < 1400
554 // compute the correct value that should have been returned from
555 // strxfrm() after the transformation has completed (MSVC strxfrm()
556 // returns a bogus result; see PR #29935)
557 xfrm_size = strlen (&res [0] + res_size);
558#endif // MSVC < 8.0
559
560 // increment the size of the result string by the number
561 // of transformed characters excluding the terminating NUL
562 // if strxfrm() transforms the empty string into the empty
563 // string, keep the terminating NUL, otherwise drop it
564 res_size += xfrm_size + (last && !*psrc && !xfrm_size);
565
566 _TRY {
567 res.resize (res_size);
568 }
569 _CATCH (...) {
570 if (pbuf != buf)
571 delete[] pbuf;
572 _RETHROW;
573 }
574 }
575
576 if (pbuf != buf)
577 delete[] pbuf;
578
579 return res;
580}
581
582
583#ifndef _RWSTD_NO_WCHAR_T
584
585# ifdef _RWSTD_NO_WCSXFRM
586
587// implements wcsxfrm() using wcstombs() and strxfrm() on platforms
588// such as some versions of BSD where the function isn't defined in
589// the C Standard Library
590static _RWSTD_SIZE_T
591__rw_wcsxfrm (wchar_t *dst, const wchar_t *src, _RWSTD_SIZE_T dstsize)
592{
593 // src must be non-null
594 _RWSTD_ASSERT (0 != src);
595
596 // dst is permitted to be null only when (dstsize == 0)
597 _RWSTD_ASSERT (0 == dstsize || dst);
598
599# ifndef _RWSTD_NO_WCSTOMBS
600
601 // convert wide string to a multibyte string before tranforming it
602 // using strxfrm() and widening the result into the destination buffer
603
604 const _RWSTD_SIZE_T srclen = _RWSTD_WCSLEN (src);
605
606 // compute the size of the temporary nearrow buffer where to narrow
607 // the source wide string to
608 const _RWSTD_SIZE_T needbytes =
609 (dstsize ? dstsize : srclen) * MB_LEN_MAX;
610
611 char narrow_buf [256];
612 char* const nbuf =
613 sizeof narrow_buf < needbytes ? new char [needbytes + 1] : narrow_buf;
614
615 _RWSTD_SIZE_T result;
616
617 const _RWSTD_SIZE_T nmbchars = wcstombs (nbuf, src, needbytes);
618
619 if (_RWSTD_SIZE_MAX == nmbchars)
620 result = _RWSTD_SIZE_MAX;
621 else {
622 // allocate a small buffer 8 times the size of the multibyte
623 // buffer (where 8 is a guess at the maximum number of bytes
624 // needed to transform the longest multibyte character)
625 char xfrm_buf [sizeof narrow_buf * 8];
626 const _RWSTD_SIZE_T xbufsize = sizeof xfrm_buf;
627 const _RWSTD_SIZE_T xbufneed = needbytes * 8;
628
629 // allocate a larger buffer if the small statically buffer
630 // isn't big enough
631 char* const xbuf =
632 xbufsize < xbufneed ? new char [xbufneed + 1] : xfrm_buf;
633
634 // transform the multibyte character string into the narrow
635 // buffer, storing the returned value
636 result = strxfrm (xbuf, nbuf, xbufneed);
637
638 if (_RWSTD_SIZE_MAX != result && dstsize) {
639 // widen the bytes (not characters) of the transformed string
640 // if the transformation was successful and the size of the
641 // destination buffer is non-zero
642
643 if (result < dstsize)
644 dstsize = result;
645
646 for (_RWSTD_SIZE_T i = 0; i != dstsize; ++i)
647 dst [i] = wchar_t (UChar (xbuf [i]));
648 }
649
650 // free the transformation buffer if dynamically allocated
651 if (xbuf != xfrm_buf)
652 delete[] xbuf;
653 }
654
655 // free the multibyte buffer if dynamically allocated
656 if (nbuf != narrow_buf)
657 delete[] nbuf;
658
659 return result;
660
661# else // if defined (_RWSTD_NO_WCSTOMBS)
662
663 _RWSTD_UNUSED (dst);
664 _RWSTD_UNUSED (src);
665 _RWSTD_UNUSED (dstsize);
666
667 // fail when there is no way to convert a wchar_t array
668 // to a multibyte string
669 return _RWSTD_SIZE_MAX;
670
671# endif // _RWSTD_NO_WCSTOMBS
672
673}
674
675# endif // _RWSTD_NO_WCSXFRM
676
677
678// same as wcsxfrm() except that it takes the number of characters
679// in an array that may contain embedded NULs; these are inserted
680// into the transformed string
681static _STD::wstring
682__rw_wcsnxfrm (const wchar_t *src, _RWSTD_SIZE_T nchars)
683{
684 _STD::wstring res;
685
686 wchar_t buf [256];
687 wchar_t *pbuf = buf;
688
689 _RWSTD_SIZE_T bufsize = sizeof buf / sizeof *buf;
690 wchar_t *psrc = buf;
691
692 while (nchars) {
693
694 typedef _STD::char_traits<wchar_t> Traits;
695
696 const wchar_t* const last = Traits::find (src, nchars, L'\0');
697
698 if (0 == last) {
699
700 // no NUL found in the initial portion of the source string
701 // that fits into the local temporary buffer; copy as many
702 // characters as fit into the buffer
703
704 if (bufsize <= nchars) {
705 if (pbuf != buf)
706 delete[] pbuf;
707 pbuf = new wchar_t [nchars + 1];
708 }
709
710 psrc = pbuf;
711 memcpy (psrc, src, nchars * sizeof *psrc);
712
713 // append a terminating NUL and decrement the number
714 // of characters that remain to be processed
715 psrc [nchars] = 0;
716 src += nchars;
717 nchars = 0;
718 }
719 else {
720
721 // terminating NUL found in the source buffer
722 nchars -= (last - src) + 1;
723 psrc = _RWSTD_CONST_CAST (wchar_t*, src);
724 src += (last - src) + 1;
725 }
726
727 // provide a destination buffer to strxfrm() in case
728 // it's buggy (such as MSVC's) and tries to write to
729 // the buffer even if it's 0
730 wchar_t just_in_case_buf [8];
731
732 const _RWSTD_SIZE_T dst_size =
733 _RWSTD_WCSXFRM (just_in_case_buf, psrc, 0);
734
735 // check for wcsxfrm() errors
736 if (_RWSTD_SIZE_MAX == dst_size)
737 return _STD::wstring ();
738
739 _RWSTD_SIZE_T res_size = res.size ();
740
741 _TRY {
742 // resize the result string to fit itself plus the result
743 // of the transformation including the terminatin NUL
744 // appended by strxfrm()
745 res.resize (res_size + dst_size + 1);
746 }
747 _CATCH (...) {
748 if (pbuf != buf)
749 delete[] pbuf;
750 _RETHROW;
751 }
752
753 // transfor the source string up to the terminating NUL
754 _RWSTD_SIZE_T xfrm_size =
755 _RWSTD_WCSXFRM (&res [0] + res_size, psrc, dst_size + 1);
756
757# if defined _MSC_VER && _MSC_VER < 1400
758 // compute the correct value that should have been returned from
759 // strxfrm() after the transformation has completed (MSVC strxfrm()
760 // returns a bogus result; see PR #29935)
761 xfrm_size = Traits::length (&res [0] + res_size);
762# endif // MSVC < 8.0
763
764 // increment the size of the result string by the number
765 // of transformed characters excluding the terminating NUL
766 // if strxfrm() transforms the empty string into the empty
767 // string, keep the terminating NUL, otherwise drop it
768 res_size += xfrm_size + (last && !*psrc && !xfrm_size);
769
770 _TRY {
771 res.resize (res_size);
772 }
773 _CATCH (...) {
774 if (pbuf != buf)
775 delete[] pbuf;
776 _RETHROW;
777 }
778 }
779
780 if (pbuf != buf)
781 delete[] pbuf;
782
783 return res;
784}
785
786#endif // _RWSTD_NO_WCHAR_T
787
788
789template <class _CharT>
790long __rw_hash (const _CharT *lo, const _CharT *hi) _THROWS (())
791{
792 // Peter Weinberger's generic hashing algorithm, adapted by Andrew
793 // Binstock from a version by Allen Holub (see Andrew Binstock,
794 // "Hashing Revisited", Dr. Dobb's Journal, April 1996)
795
796 const int long_bits = _RWSTD_CHAR_BIT * int (sizeof (long));
797 const int one_eighth = long_bits / 8;
798 const int three_fourths = long_bits * 3 / 4;
799 // subexpression parenthesized to prevent MSVC 13.00 warning C4554
800 const long hi_bits = ~0L << (long_bits - one_eighth);
801
802 long res = 0;
803
804 for ( ; lo != hi; ++lo) {
805 typedef _STD::char_traits<_CharT> _Traits;
806
807 res = (res << one_eighth) + _Traits::to_int_type (*lo);
808
809 const long tmp = res & hi_bits;
810 if (tmp)
811 res = (res ^ (tmp >> three_fourths)) & ~hi_bits;
812 }
813
814 return res;
815}
816
817#ifndef _RWSTD_NO_INSTANTIATE
818# ifndef _RWSTD_NO_EXPLICIT_FUNC_INSTANTIATION
819
820// explicitly instantiate for compilers with automatic template
821// instantiation that don't emit symbols for implicitly instantiated
822// templates even of they are completely defined in .cpp files
823// (e.g., Compaq C++)
824
825template long __rw_hash (const char*, const char*) _THROWS(());
826
827# ifndef _RWSTD_NO_WCHAR_T
828
829template long __rw_hash (const wchar_t*, const wchar_t*) _THROWS(());
830
831# endif // _RWSTD_NO_WCHAR_T
832
833# endif // _RWSTD_NO_EXPLICIT_FUNC_INSTANTIATION
834#endif // _RWSTD_NO_INSTANTIATE
835
836
837} // namespace __rw
838
839
841
842
843_RW::__rw_facet_id collate<char>::id;
844
845
846// outlined to avoid generating a vtable in each translation unit
847// that uses the class
848/* virtual */ collate<char>::
849~collate () /* nothrow */
850{
851 // no-op
852}
853
854
855int collate<char>::
856do_compare (const char_type *__lo1, const char_type *__hi1,
857 const char_type *__lo2, const char_type *__hi2) const
858{
859 _RWSTD_ASSERT (__lo1 <= __hi1 && __lo2 <= __hi2);
860
861 const _RWSTD_SIZE_T __len1 = __hi1 - __lo1;
862 const _RWSTD_SIZE_T __len2 = __hi2 - __lo2;
863
864 const int cmp = memcmp (__lo1, __lo2, __len1 < __len2 ? __len1 : __len2);
865
866 if (cmp)
867 return cmp < 0 ? -1 : 1;
868
869 return __len1 < __len2 ? -1 : __len2 < __len1 ? +1 : 0;
870}
871
872
873collate<char>::string_type collate<char>::
874do_transform (const char_type *__lo, const char_type *__hi) const
875{
876 _RWSTD_ASSERT (0 != __lo);
877 _RWSTD_ASSERT (__lo <= __hi);
878
879 return string_type (__lo, size_t (__hi - __lo));
880}
881
882
883long collate<char>::
884do_hash (const char_type *__lo, const char_type *__hi) const
885{
886 // hash the result of do_transform, so that keys that transform equally
887 // will hash equally, as per 22.2.4.1.2, p3
888
889 const string_type __str = do_transform (__lo, __hi);
890
891 __lo = __str.data ();
892 __hi = __lo + __str.length ();
893
894 const long res = _RW::__rw_hash (__lo, __hi);
895
896 return res;
897}
898
899
900// outlined to avoid generating a vtable in each translation unit
901// that uses the class
902/* virtual */ collate_byname<char>::
903~collate_byname () /* nothrow */
904{
905 // no-op
906}
907
908
909int collate_byname<char>::
910do_compare (const char* low1, const char* high1,
911 const char* low2, const char* high2) const
912{
913 const string_type s1 = do_transform (low1, high1);
914 const string_type s2 = do_transform (low2, high2);
915
916 // FIXME: optimize: doing a full transformation of the two
917 // strings is not necessary, it might be quicker to only do
918 // a partial transformation
919 const int cmp = s1.compare (s2);
920
921 // normalize
922 return cmp < 0 ? -1 : cmp ? 1 : 0;
923}
924
925
926collate_byname<char>::string_type
927collate_byname<char>::
928do_transform (const char* low, const char* high) const
929{
930 _RWSTD_ASSERT (low <= high);
931
932 const int ccvt_cat = _RW::__rw_get_cat ((_C_wcodecvt_byname + 1) / 2);
933
934 _RW::__rw_collate_t* const impl =
935 _RWSTD_CONST_CAST (_RW::__rw_collate_t*,
936 _RWSTD_STATIC_CAST (const _RW::__rw_collate_t*, _C_data ()));
937
938 if (!impl || (this->_C_opts & this->_C_use_libc)) {
939
940 // set the global libc locale in a thread-safe way
941 const _RW::__rw_setlocale clocale (_C_name, _RWSTD_LC_COLLATE);
942
943 return _RW::__rw_strnxfrm (low, high - low);
944 }
945
946 _RWSTD_ASSERT (0 != impl);
947
948 // the maximum size that we could need to hold all the weight offsets
949 // is high - low
950 _RW::__rw_pod_array<const unsigned int*, 1024> indexes;
951
952 // first go through the string getting a weight offset for
953 // each character, in the process check for collating elements.
954 const char* tmp_lo = low;
955
956 for (; tmp_lo < high; tmp_lo++) {
957 const char* tmp_lo2 = tmp_lo;
958 int ret = _RW::__rw_get_n_ce_offset (impl, &tmp_lo2, high);
959
960 if (ret == -1) {
961 tmp_lo2 = tmp_lo;
962 ret = _RW::__rw_get_char_offset (impl, &tmp_lo2, high);
963 if (ret == -1) {
964 // The character is not explicitely defined, but it
965 // may have been defined implicitly by UNDEFINED.
966 // because we cannot tell the difference between
967 // an UNDEFINED character and an invalid character
968 // in the collate database we must use the codecvt
969 // database to discover this information
970 if (impl->undefined_optimization) {
971
972 _RWSTD_SIZE_T size;
973
974 const _RW::__rw_codecvt_t *cvt =
975 _RWSTD_STATIC_CAST (const _RW::__rw_codecvt_t*,
976 _RW::__rw_get_facet_data (
977 ccvt_cat, size, _C_name,
978 impl->codeset_name ()));
979
980 if (_RW::__rw_is_invalid (cvt->n_to_w_tab(), tmp_lo2))
981 return 0;
982
983 const unsigned int *pwt =
984 impl->get_weight (impl->undefined_weight_idx);
985 indexes.append (&pwt, 1);
986
987 tmp_lo = tmp_lo2;
988 }
989 }
990 else {
991 const unsigned int *pwt = impl->get_weight (ret);
992 indexes.append (&pwt, 1);
993 tmp_lo = tmp_lo2;
994 }
995 }
996 else {
997 // we found a collating element
998 const unsigned int *pwt = impl->get_weight (ret);
999 indexes.append (&pwt, 1);
1000 tmp_lo = tmp_lo2;
1001 }
1002 }
1003 // now process the weights
1004 string_type out;
1005 _RW::__rw_process_offsets (impl, indexes.data (),
1006 indexes.data () + indexes.size (), out);
1007
1008 return out;
1009}
1010
1011
1012#ifndef _RWSTD_NO_WCHAR_T
1013
1014_RW::__rw_facet_id collate<wchar_t>::id;
1015
1016
1017// outlined to avoid generating a vtable in each translation unit
1018// that uses the class
1019/* virtual */ collate<wchar_t>::
1020~collate () /* nothrow */
1021{
1022 // no-op
1023}
1024
1025
1026int collate<wchar_t>::
1027do_compare (const char_type *__lo1, const char_type *__hi1,
1028 const char_type *__lo2, const char_type *__hi2) const
1029{
1030 _RWSTD_ASSERT (__lo1 <= __hi1 && __lo2 <= __hi2);
1031
1032 const _RWSTD_SIZE_T __len1 = __hi1 - __lo1;
1033 const _RWSTD_SIZE_T __len2 = __hi2 - __lo2;
1034
1035#ifndef _RWSTD_NO_WMEMCMP
1036
1037 const int cmp = wmemcmp (__lo1, __lo2, __len1 < __len2 ? __len1 : __len2);
1038
1039 if (cmp)
1040 return cmp < 0 ? -1 : 1;
1041
1042#else // if defined (_RWSTD_NO_WMEMCMP)
1043
1044 for (_RWSTD_SIZE_T __len = __len1 < __len2 ? __len1 : __len2;
1045 __len--; ++__lo1, ++__lo2) {
1046
1047 typedef string_type::traits_type _Traits;
1048 typedef _Traits::int_type _Int;
1049
1050 // avoid arithmetic on unknown char types
1051 const _Int __i1 = _Traits::to_int_type (*__lo1);
1052 const _Int __i2 = _Traits::to_int_type (*__lo2);
1053
1054 // use int_type to prevent signed versus unsigned char comparison
1055 if (!_Traits::eq_int_type (__i1, __i2))
1056 return __i1 < __i2 ? -1 : 1;
1057 }
1058
1059#endif // _RWSTD_NO_WMEMCMP
1060
1061 return __len1 < __len2 ? -1 : __len2 < __len1 ? +1 : 0;
1062}
1063
1064
1065collate<wchar_t>::string_type collate<wchar_t>::
1066do_transform (const char_type *__lo, const char_type *__hi) const
1067{
1068 _RWSTD_ASSERT (0 != __lo);
1069 _RWSTD_ASSERT (__lo <= __hi);
1070
1071 return string_type (__lo, size_t (__hi - __lo));
1072}
1073
1074
1075long collate<wchar_t>::
1076do_hash (const char_type *__lo, const char_type *__hi) const
1077{
1078 // hash the result of do_transform, so that keys that transform equally
1079 // will hash equally, as per 22.2.4.1.2, p3
1080
1081 const string_type __str = do_transform (__lo, __hi);
1082
1083 __lo = __str.data ();
1084 __hi = __lo + __str.length ();
1085
1086 const long res = _RW::__rw_hash (__lo, __hi);
1087
1088 return res;
1089}
1090
1091
1092// outlined to avoid generating a vtable in each translation unit
1093// that uses the class
1094/* virtual */ collate_byname<wchar_t>::
1095~collate_byname () /* nothrow */
1096{
1097 // no-op
1098}
1099
1100
1101int collate_byname<wchar_t>::
1102do_compare (const wchar_t* low1, const wchar_t* high1,
1103 const wchar_t* low2, const wchar_t* high2) const
1104{
1105 if (this->_C_opts & this->_C_use_libstd) {
1106 const string_type s1 = do_transform (low1, high1);
1107 const string_type s2 = do_transform (low2, high2);
1108
1109 // FIXME: optimize
1110 return s1.compare (s2);
1111 }
1112
1113#ifndef _RWSTD_NO_WCSCOLL
1114
1115 // use the system C library to compare the strings
1116
1117 _RW::__rw_setlocale clocale (this->_C_name, _RWSTD_LC_COLLATE);
1118
1119 const _RWSTD_SIZE_T len1 = high1 - low1;
1120 const _RWSTD_SIZE_T len2 = high2 - low2;
1121 const _RWSTD_SIZE_T len = len1 + len2;
1122
1123 // small local buffer
1124 wchar_t local_buffer [256];
1125 const _RWSTD_SIZE_T bufsize = sizeof local_buffer / sizeof *local_buffer;
1126
1127 // allocate only if local buffer is too small
1128 wchar_t* const wbuf =
1129 len + 2 >= bufsize ? new wchar_t [len + 2] : local_buffer;
1130
1131 // copy and null-terminate first sequence
1132 char_traits<wchar_t>::copy (wbuf, low1, len1);
1133 wbuf [len1] = '\0';
1134
1135 // append and null-terminate first sequence
1136 char_traits<wchar_t>::copy (wbuf + len1 + 1, low2, len2);
1137 wbuf [len1 + 1 + len2] = '\0';
1138
1139 // compare sequences using wcscoll()
1140 const int result = wcscoll (wbuf, wbuf + len1 + 1);
1141
1142 // deallocate only if allocated
1143 if (wbuf != local_buffer)
1144 delete[] wbuf;
1145
1146 return result ? result > 0 ? 1 : -1 : 0;
1147
1148#else // if defined (_RWSTD_NO_WCSCOLL)
1149
1150 // transform strings first and compare the transformed results
1151 const string_type s1 = do_transform (low1, high1);
1152 const string_type s2 = do_transform (low2, high2);
1153
1154 return s1.compare (s2);
1155
1156#endif // _RWSTD_NO_WCSCOLL
1157
1158}
1159
1160
1161collate_byname<wchar_t>::string_type
1162collate_byname<wchar_t>::
1163do_transform (const wchar_t* low, const wchar_t* high) const
1164{
1165 const int ccvt_cat = _RW::__rw_get_cat ((_C_wcodecvt_byname + 1) / 2);
1166
1167 _RW::__rw_collate_t *impl =
1168 _RWSTD_CONST_CAST (_RW::__rw_collate_t*, _RWSTD_STATIC_CAST (
1169 const _RW::__rw_collate_t*, _C_data ()));
1170
1171 if (!impl || (this->_C_opts & this->_C_use_libc)) {
1172
1173 // set the global libc locale in a thread-safe way
1174 const _RW::__rw_setlocale clocale (_C_name, _RWSTD_LC_COLLATE);
1175
1176 return _RW::__rw_wcsnxfrm (low, high - low);
1177 }
1178 else {
1179 _RWSTD_ASSERT (0 != impl);
1180 // the maximum size that we could need to hold all the weight offsets
1181 // is high - low
1182 _RW::__rw_pod_array<const unsigned int*, 1024> indexes;
1183
1184 // first go through the string getting a weight offset for
1185 // each character, in the process check for collating elements.
1186 for (const wchar_t* tmp_lo =low; tmp_lo < high; tmp_lo++) {
1187 const wchar_t* tmp_lo2 = tmp_lo;
1188 int ret = _RW::__rw_get_w_ce_offset (impl, &tmp_lo2, high);
1189 if (ret == -1) {
1190 tmp_lo2 = tmp_lo;
1191 ret = _RW::__rw_get_wchar_offset (impl, &tmp_lo2, high);
1192 if (ret == -1) {
1193 // The character is not explicitely defined, but it
1194 // may have been defined implicitly by UNDEFINED.
1195 // because we cannot tell the difference between
1196 // an UNDEFINED character and an invalid character
1197 // in the collate database we must use the codecvt
1198 // database to discover this information
1199 if (impl->undefined_optimization) {
1200 _RWSTD_SIZE_T size;
1201 const _RW::__rw_codecvt_t *cvt =
1202 _RWSTD_STATIC_CAST (const _RW::__rw_codecvt_t*,
1203 _RW::__rw_get_facet_data (
1204 ccvt_cat, size, _C_name,
1205 impl->codeset_name ()));
1206
1207 char tmp [_RWSTD_MB_MAX];
1208
1209 const _RWSTD_SIZE_T nbytes =
1210 _RW::__rw_itoutf8 (*tmp_lo2, tmp);
1211
1212 tmp [nbytes] = '\0';
1213
1214 if (_RW::__rw_is_invalid (cvt->w_to_n_tab (), tmp))
1215 return 0;
1216
1217 const unsigned int *pwt =
1218 impl->get_weight (impl->undefined_weight_idx);
1219 indexes.append (&pwt, 1);
1220 tmp_lo = tmp_lo2;
1221 }
1222 }
1223 else {
1224 const unsigned int *pwt = impl->get_weight (ret);
1225 indexes.append (&pwt, 1);
1226 tmp_lo = tmp_lo2;
1227 }
1228 }
1229 else {
1230 // we found a collating element
1231 const unsigned int *pwt = impl->get_weight (ret);
1232 indexes.append (&pwt, 1);
1233 tmp_lo = tmp_lo2;
1234 }
1235 }
1236 // now process the weights
1237 string_type out;
1238 _RW::__rw_process_offsets (impl, indexes.data (),
1239 indexes.data () + indexes.size (), out);
1240
1241 return out;
1242 }
1243}
1244
1245#endif // _RWSTD_NO_WCHAR_T
1246
1247
1248
1249} // namespace std
#define c2
Definition 17.names.cpp:253
#define i
Definition 17.names.cpp:126
#define s1
Definition 17.names.cpp:242
#define cmp
Definition 17.names.cpp:458
#define start
Definition 17.names.cpp:547
#define nchars
Definition 17.names.cpp:502
#define s2
Definition 17.names.cpp:268
#define res
Definition 17.names.cpp:531
#define last
Definition 17.names.cpp:487
#define Traits
Definition 17.names.cpp:556
#define c1
Definition 17.names.cpp:227
#define CharT
Definition 17.names.cpp:457
#define buf
Definition 17.names.cpp:452
#define tmp
Definition 17.names.cpp:553
#define len
Definition 17.names.cpp:488
volatile int result
const int end
const int out
const int cur
#define _THROWS()
unsigned short wchar_t
#define _RWSTD_DLLIMPORT
Definition _config.h:391
#define _RETHROW
Definition _defs.h:853
#define _RWSTD_UNUSED(arg)
Definition _defs.h:972
#define _RWSTD_INTERNAL
Definition _defs.h:1005
#define _RWSTD_STATIC_CAST(T, x)
Definition _defs.h:534
#define _LIBC_THROWS()
Definition _defs.h:1152
#define _TRY
Definition _defs.h:850
#define _RWSTD_NAMESPACE(name)
Definition _defs.h:567
#define _RWSTD_ASSERT(ignore)
Definition _defs.h:1108
#define _CATCH(ex)
Definition _defs.h:851
#define _RWSTD_CONST_CAST(T, x)
Definition _defs.h:536
#define _RWSTD_WCSLEN
Definition _traits.h:177
#define MB_LEN_MAX
Definition limits.h:100
Definition json.h:5363
#define _RWSTD_MB_MAX
Definition collate.cpp:65
unsigned char UChar
Definition collate.cpp:122
#define _RWSTD_WCSXFRM
Definition collate.cpp:102