]>
Commit | Line | Data |
---|---|---|
5e93f39f | 1 | // -*- C++ -*- |
5305b1ae | 2 | |
5e93f39f PR |
3 | // Testing character type and state type with char_traits and codecvt |
4 | // specializations for the C++ library testsuite. | |
5 | // | |
748086b7 | 6 | // Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 |
fa52081d | 7 | // Free Software Foundation, Inc. |
5e93f39f PR |
8 | // |
9 | // This file is part of the GNU ISO C++ Library. This library is free | |
10 | // software; you can redistribute it and/or modify it under the | |
11 | // terms of the GNU General Public License as published by the | |
748086b7 | 12 | // Free Software Foundation; either version 3, or (at your option) |
5e93f39f PR |
13 | // any later version. |
14 | // | |
15 | // This library is distributed in the hope that it will be useful, | |
16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | // GNU General Public License for more details. | |
19 | // | |
20 | // You should have received a copy of the GNU General Public License along | |
748086b7 JJ |
21 | // with this library; see the file COPYING3. If not see |
22 | // <http://www.gnu.org/licenses/>. | |
5e93f39f | 23 | // |
5e93f39f PR |
24 | |
25 | #ifndef _GLIBCXX_TESTSUITE_CHARACTER_H | |
26 | #define _GLIBCXX_TESTSUITE_CHARACTER_H | |
27 | ||
5305b1ae | 28 | #include <climits> |
5e93f39f PR |
29 | #include <string> // for char_traits |
30 | #include <locale> // for codecvt | |
f56fe8ff | 31 | #include <algorithm> // for transform |
5305b1ae | 32 | #include <ext/pod_char_traits.h> |
5e93f39f PR |
33 | |
34 | namespace __gnu_test | |
35 | { | |
821503db | 36 | struct pod_int |
5e93f39f | 37 | { |
821503db | 38 | int value; |
fa52081d | 39 | |
734f5023 | 40 | #if __cplusplus >= 201103L |
fa52081d PC |
41 | // For std::iota. |
42 | pod_int& | |
43 | operator++() | |
44 | { | |
45 | ++value; | |
46 | return *this; | |
47 | } | |
48 | #endif | |
5e93f39f | 49 | }; |
fa52081d | 50 | |
4f99f3d0 BK |
51 | // For 20.1 requirements for instantiable type: equality comparable |
52 | // and less than comparable. | |
821503db BK |
53 | inline bool |
54 | operator==(const pod_int& lhs, const pod_int& rhs) | |
55 | { return lhs.value == rhs.value; } | |
56 | ||
ce345590 | 57 | inline bool |
821503db BK |
58 | operator<(const pod_int& lhs, const pod_int& rhs) |
59 | { return lhs.value < rhs.value; } | |
ce345590 | 60 | |
4f99f3d0 BK |
61 | // For 26 numeric algorithms requirements, need addable, |
62 | // subtractable, multiplicable. | |
63 | inline pod_int | |
64 | operator+(const pod_int& lhs, const pod_int& rhs) | |
65 | { | |
66 | pod_int ret = { lhs.value + rhs.value }; | |
67 | return ret; | |
68 | } | |
69 | ||
70 | inline pod_int | |
71 | operator-(const pod_int& lhs, const pod_int& rhs) | |
72 | { | |
73 | pod_int ret = { lhs.value - rhs.value }; | |
74 | return ret; | |
75 | } | |
76 | ||
77 | inline pod_int | |
78 | operator*(const pod_int& lhs, const pod_int& rhs) | |
79 | { | |
80 | pod_int ret = { lhs.value * rhs.value }; | |
81 | return ret; | |
82 | } | |
83 | ||
821503db | 84 | struct pod_state |
5e93f39f | 85 | { |
821503db | 86 | unsigned long value; |
5e93f39f | 87 | }; |
5305b1ae | 88 | |
821503db BK |
89 | inline bool |
90 | operator==(const pod_state& lhs, const pod_state& rhs) | |
91 | { return lhs.value == rhs.value; } | |
5305b1ae BK |
92 | |
93 | inline bool | |
821503db BK |
94 | operator<(const pod_state& lhs, const pod_state& rhs) |
95 | { return lhs.value < rhs.value; } | |
5305b1ae | 96 | |
821503db BK |
97 | // Alternate character types. |
98 | using __gnu_cxx::character; | |
99 | typedef character<unsigned char, pod_int, pod_state> pod_char; | |
100 | typedef character<unsigned char, unsigned int, pod_state> pod_uchar; | |
101 | typedef character<unsigned short, unsigned int> pod_ushort; | |
a70c902e | 102 | typedef character<unsigned int, unsigned long> pod_uint; |
9c12301f | 103 | } |
5e93f39f | 104 | |
3cbc7af0 BK |
105 | namespace __gnu_cxx |
106 | { | |
821503db BK |
107 | // Specializations. |
108 | // pod_char | |
5e93f39f | 109 | template<> |
821503db | 110 | template<typename V2> |
9c12301f MM |
111 | inline __gnu_test::pod_char::char_type |
112 | __gnu_test::pod_char::char_type::from(const V2& v) | |
5e93f39f | 113 | { |
821503db BK |
114 | char_type ret = { static_cast<value_type>(v.value) }; |
115 | return ret; | |
5e93f39f PR |
116 | } |
117 | ||
821503db BK |
118 | template<> |
119 | template<typename V2> | |
120 | inline V2 | |
9c12301f | 121 | __gnu_test::pod_char::char_type::to(const char_type& c) |
5e93f39f | 122 | { |
821503db BK |
123 | V2 ret = { c.value }; |
124 | return ret; | |
5e93f39f | 125 | } |
821503db | 126 | |
821503db BK |
127 | template<> |
128 | template<typename V2> | |
9c12301f MM |
129 | inline __gnu_test::pod_uchar::char_type |
130 | __gnu_test::pod_uchar::char_type::from(const V2& v) | |
5e93f39f PR |
131 | { |
132 | char_type ret; | |
821503db | 133 | ret.value = (v >> 5); |
5e93f39f PR |
134 | return ret; |
135 | } | |
136 | ||
821503db BK |
137 | template<> |
138 | template<typename V2> | |
139 | inline V2 | |
9c12301f | 140 | __gnu_test::pod_uchar::char_type::to(const char_type& c) |
821503db | 141 | { return static_cast<V2>(c.value << 5); } |
799a6e36 | 142 | } // namespace __gnu_test |
5e93f39f | 143 | |
821503db BK |
144 | namespace std |
145 | { | |
5e93f39f PR |
146 | // codecvt specialization |
147 | // | |
148 | // The conversion performed by the specialization is not supposed to | |
149 | // be useful, rather it has been designed to demonstrate the | |
150 | // essential features of stateful conversions: | |
151 | // * Number and value of bytes for each internal character depends on the | |
152 | // state in addition to the character itself. | |
153 | // * Unshift produces an unshift sequence and resets the state. On input | |
154 | // the unshift sequence causes the state to be reset. | |
155 | // | |
156 | // The conversion for output is as follows: | |
157 | // 1. Calculate the value tmp by xor-ing the state and the internal | |
158 | // character | |
159 | // 2. Split tmp into either two or three bytes depending on the value of | |
160 | // state. Output those bytes. | |
161 | // 3. tmp becomes the new value of state. | |
162 | template<> | |
821503db BK |
163 | class codecvt<__gnu_test::pod_uchar, char, __gnu_test::pod_state> |
164 | : public __codecvt_abstract_base<__gnu_test::pod_uchar, char, | |
165 | __gnu_test::pod_state> | |
5e93f39f PR |
166 | { |
167 | public: | |
821503db BK |
168 | typedef codecvt_base::result result; |
169 | typedef __gnu_test::pod_uchar intern_type; | |
170 | typedef char extern_type; | |
171 | typedef __gnu_test::pod_state state_type; | |
172 | typedef __codecvt_abstract_base<intern_type, extern_type, state_type> | |
173 | base_type; | |
174 | ||
175 | explicit codecvt(size_t refs = 0) : base_type(refs) | |
5e93f39f PR |
176 | { } |
177 | ||
5e93f39f PR |
178 | static locale::id id; |
179 | ||
180 | protected: | |
181 | ~codecvt() | |
182 | { } | |
183 | ||
184 | virtual result | |
185 | do_out(state_type& state, const intern_type* from, | |
186 | const intern_type* from_end, const intern_type*& from_next, | |
187 | extern_type* to, extern_type* to_limit, | |
188 | extern_type*& to_next) const | |
189 | { | |
190 | while (from < from_end && to < to_limit) | |
191 | { | |
821503db BK |
192 | unsigned char tmp = (state.value ^ from->value); |
193 | if (state.value & 0x8) | |
5e93f39f PR |
194 | { |
195 | if (to >= to_limit - 2) | |
196 | break; | |
197 | *to++ = (tmp & 0x7); | |
198 | *to++ = ((tmp >> 3) & 0x7); | |
199 | *to++ = ((tmp >> 6) & 0x3); | |
200 | } | |
201 | else | |
202 | { | |
203 | if (to >= to_limit - 1) | |
204 | break; | |
205 | *to++ = (tmp & 0xf); | |
206 | *to++ = ((tmp >> 4) & 0xf); | |
207 | } | |
821503db | 208 | state.value = tmp; |
5e93f39f PR |
209 | ++from; |
210 | } | |
211 | ||
212 | from_next = from; | |
213 | to_next = to; | |
214 | return (from < from_end) ? partial : ok; | |
215 | } | |
216 | ||
217 | virtual result | |
218 | do_in(state_type& state, const extern_type* from, | |
219 | const extern_type* from_end, const extern_type*& from_next, | |
220 | intern_type* to, intern_type* to_limit, | |
221 | intern_type*& to_next) const | |
222 | { | |
223 | while (from < from_end && to < to_limit) | |
224 | { | |
225 | unsigned char c = *from; | |
226 | if (c & 0xc0) | |
227 | { | |
228 | // Unshift sequence | |
821503db | 229 | state.value &= c; |
5e93f39f PR |
230 | ++from; |
231 | continue; | |
232 | } | |
233 | ||
234 | unsigned char tmp; | |
821503db | 235 | if (state.value & 0x8) |
5e93f39f PR |
236 | { |
237 | if (from >= from_end - 2) | |
238 | break; | |
239 | tmp = (*from++ & 0x7); | |
240 | tmp |= ((*from++ << 3) & 0x38); | |
241 | tmp |= ((*from++ << 6) & 0xc0); | |
242 | } | |
243 | else | |
244 | { | |
245 | if (from >= from_end - 1) | |
246 | break; | |
247 | tmp = (*from++ & 0xf); | |
248 | tmp |= ((*from++ << 4) & 0xf0); | |
249 | } | |
821503db BK |
250 | to->value = (tmp ^ state.value); |
251 | state.value = tmp; | |
5e93f39f PR |
252 | ++to; |
253 | } | |
254 | ||
255 | from_next = from; | |
256 | to_next = to; | |
257 | return (from < from_end) ? partial : ok; | |
258 | } | |
259 | ||
260 | virtual result | |
261 | do_unshift(state_type& state, extern_type* to, extern_type* to_limit, | |
262 | extern_type*& to_next) const | |
263 | { | |
264 | for (unsigned int i = 0; i < CHAR_BIT; ++i) | |
265 | { | |
266 | unsigned int mask = (1 << i); | |
821503db | 267 | if (state.value & mask) |
5e93f39f PR |
268 | { |
269 | if (to == to_limit) | |
270 | { | |
271 | to_next = to; | |
272 | return partial; | |
273 | } | |
274 | ||
821503db | 275 | state.value &= ~mask; |
5e93f39f PR |
276 | *to++ = static_cast<unsigned char>(~mask); |
277 | } | |
278 | } | |
279 | ||
280 | to_next = to; | |
821503db | 281 | return state.value == 0 ? ok : error; |
5e93f39f PR |
282 | } |
283 | ||
284 | virtual int | |
285 | do_encoding() const throw() | |
286 | { return -1; } | |
287 | ||
288 | virtual bool | |
289 | do_always_noconv() const throw() | |
290 | { return false; } | |
291 | ||
292 | virtual int | |
293 | do_length(state_type& state, const extern_type* from, | |
294 | const extern_type* end, size_t max) const | |
295 | { | |
296 | const extern_type* beg = from; | |
3531cf5e | 297 | while (from < end) |
5e93f39f PR |
298 | { |
299 | unsigned char c = *from; | |
300 | if (c & 0xc0) | |
301 | { | |
302 | // Unshift sequence | |
821503db | 303 | state.value &= c; |
5e93f39f PR |
304 | ++from; |
305 | continue; | |
306 | } | |
3531cf5e DK |
307 | |
308 | if (max == 0) break; | |
5e93f39f PR |
309 | |
310 | unsigned char tmp; | |
821503db | 311 | if (state.value & 0x8) |
5e93f39f PR |
312 | { |
313 | if (from >= end - 2) | |
314 | break; | |
315 | tmp = (*from++ & 0x7); | |
316 | tmp |= ((*from++ << 3) & 0x38); | |
317 | tmp |= ((*from++ << 6) & 0xc0); | |
318 | } | |
319 | else | |
320 | { | |
321 | if (from >= end - 1) | |
322 | break; | |
323 | tmp = (*from++ & 0xf); | |
324 | tmp |= ((*from++ << 4) & 0xf0); | |
325 | } | |
821503db | 326 | state.value = tmp; |
5e93f39f PR |
327 | --max; |
328 | } | |
329 | return from - beg; | |
330 | } | |
331 | ||
332 | // Maximum 8 bytes unshift sequence followed by max 3 bytes for | |
333 | // one character. | |
334 | virtual int | |
335 | do_max_length() const throw() | |
336 | { return 11; } | |
337 | }; | |
338 | ||
5305b1ae | 339 | template<> |
821503db BK |
340 | class ctype<__gnu_test::pod_uchar> |
341 | : public __ctype_abstract_base<__gnu_test::pod_uchar> | |
5305b1ae | 342 | { |
821503db BK |
343 | public: |
344 | typedef __gnu_test::pod_uchar char_type; | |
5305b1ae | 345 | |
821503db BK |
346 | explicit ctype(size_t refs = 0) |
347 | : __ctype_abstract_base<__gnu_test::pod_uchar>(refs) { } | |
5305b1ae | 348 | |
821503db | 349 | static locale::id id; |
5305b1ae | 350 | |
821503db BK |
351 | protected: |
352 | ~ctype() | |
353 | { } | |
5305b1ae | 354 | |
821503db | 355 | virtual bool |
8b5bc374 | 356 | do_is(mask, char_type) const |
821503db BK |
357 | { return false; } |
358 | ||
359 | virtual const char_type* | |
360 | do_is(const char_type* low, const char_type* high, mask* vec) const | |
5305b1ae | 361 | { |
821503db BK |
362 | fill_n(vec, high - low, mask()); |
363 | return high; | |
5305b1ae BK |
364 | } |
365 | ||
821503db | 366 | virtual const char_type* |
8b5bc374 | 367 | do_scan_is(mask, const char_type*, const char_type* high) const |
821503db BK |
368 | { return high; } |
369 | ||
370 | virtual const char_type* | |
8b5bc374 | 371 | do_scan_not(mask, const char_type* low, const char_type*) const |
821503db BK |
372 | { return low; } |
373 | ||
374 | virtual char_type | |
375 | do_toupper(char_type c) const | |
376 | { return c; } | |
5305b1ae | 377 | |
821503db | 378 | virtual const char_type* |
8b5bc374 | 379 | do_toupper(char_type*, const char_type* high) const |
821503db BK |
380 | { return high; } |
381 | ||
382 | virtual char_type | |
383 | do_tolower(char_type c) const | |
384 | { return c; } | |
385 | ||
386 | virtual const char_type* | |
8b5bc374 | 387 | do_tolower(char_type*, const char_type* high) const |
821503db BK |
388 | { return high; } |
389 | ||
390 | virtual char_type | |
391 | do_widen(char c) const | |
392 | { return __gnu_test::pod_uchar::from<char>(c); } | |
393 | ||
394 | virtual const char* | |
395 | do_widen(const char* low, const char* high, char_type* dest) const | |
5305b1ae | 396 | { |
821503db BK |
397 | transform(low, high, dest, &__gnu_test::pod_uchar::from<char>); |
398 | return high; | |
5305b1ae BK |
399 | } |
400 | ||
821503db BK |
401 | virtual char |
402 | do_narrow(char_type, char dfault) const | |
403 | { return dfault; } | |
404 | ||
405 | virtual const char_type* | |
406 | do_narrow(const char_type* low, const char_type* high, | |
407 | char dfault, char* dest) const | |
5305b1ae | 408 | { |
821503db BK |
409 | fill_n(dest, high - low, dfault); |
410 | return high; | |
5305b1ae BK |
411 | } |
412 | }; | |
a70c902e PC |
413 | |
414 | // numpunct specializations | |
415 | template<> | |
416 | class numpunct<__gnu_test::pod_uint> | |
417 | : public locale::facet | |
418 | { | |
419 | public: | |
420 | typedef __gnu_test::pod_uint char_type; | |
421 | typedef basic_string<char_type> string_type; | |
422 | ||
423 | static locale::id id; | |
424 | ||
425 | explicit | |
426 | numpunct(size_t refs = 0) | |
427 | : locale::facet(refs) | |
428 | { } | |
429 | ||
430 | char_type | |
431 | decimal_point() const | |
432 | { return this->do_decimal_point(); } | |
433 | ||
434 | char_type | |
435 | thousands_sep() const | |
436 | { return this->do_thousands_sep(); } | |
437 | ||
438 | string | |
439 | grouping() const | |
440 | { return this->do_grouping(); } | |
441 | ||
442 | string_type | |
443 | truename() const | |
444 | { return this->do_truename(); } | |
445 | ||
446 | string_type | |
447 | falsename() const | |
448 | { return this->do_falsename(); } | |
449 | ||
450 | protected: | |
451 | ~numpunct() | |
452 | { } | |
453 | ||
454 | virtual char_type | |
455 | do_decimal_point() const | |
456 | { return char_type(); } | |
457 | ||
458 | virtual char_type | |
459 | do_thousands_sep() const | |
460 | { return char_type(); } | |
461 | ||
462 | virtual string | |
463 | do_grouping() const | |
464 | { return string(); } | |
465 | ||
466 | virtual string_type | |
467 | do_truename() const | |
468 | { return string_type(); } | |
469 | ||
470 | virtual string_type | |
471 | do_falsename() const | |
472 | { return string_type(); } | |
473 | }; | |
474 | ||
475 | template<> | |
476 | class moneypunct<__gnu_test::pod_uint> | |
477 | : public locale::facet, public money_base | |
478 | { | |
479 | public: | |
480 | typedef __gnu_test::pod_uint char_type; | |
481 | typedef basic_string<char_type> string_type; | |
482 | ||
483 | static locale::id id; | |
484 | static const bool intl = false; | |
485 | ||
486 | explicit | |
487 | moneypunct(size_t refs = 0) | |
488 | : locale::facet(refs) | |
489 | { } | |
490 | ||
491 | char_type | |
492 | decimal_point() const | |
493 | { return this->do_decimal_point(); } | |
494 | ||
495 | char_type | |
496 | thousands_sep() const | |
497 | { return this->do_thousands_sep(); } | |
498 | ||
499 | string | |
500 | grouping() const | |
501 | { return this->do_grouping(); } | |
502 | ||
503 | string_type | |
504 | curr_symbol() const | |
505 | { return this->do_curr_symbol(); } | |
506 | ||
507 | string_type | |
508 | positive_sign() const | |
509 | { return this->do_positive_sign(); } | |
510 | ||
511 | string_type | |
512 | negative_sign() const | |
513 | { return this->do_negative_sign(); } | |
514 | ||
515 | int | |
516 | frac_digits() const | |
517 | { return this->do_frac_digits(); } | |
518 | ||
519 | pattern | |
520 | pos_format() const | |
521 | { return this->do_pos_format(); } | |
522 | ||
523 | pattern | |
524 | neg_format() const | |
525 | { return this->do_neg_format(); } | |
526 | ||
527 | protected: | |
528 | ~moneypunct() | |
529 | { } | |
530 | ||
531 | virtual char_type | |
532 | do_decimal_point() const | |
533 | { return char_type(); } | |
534 | ||
535 | virtual char_type | |
536 | do_thousands_sep() const | |
537 | { return char_type(); } | |
538 | ||
539 | virtual string | |
540 | do_grouping() const | |
541 | { return string(); } | |
542 | ||
543 | virtual string_type | |
544 | do_curr_symbol() const | |
545 | { return string_type(); } | |
546 | ||
547 | string_type | |
548 | do_positive_sign() const | |
549 | { return string_type(); } | |
550 | ||
551 | string_type | |
552 | do_negative_sign() const | |
553 | { return string_type(); } | |
554 | ||
555 | int | |
556 | do_frac_digits() const | |
557 | { return 0; } | |
558 | ||
559 | pattern | |
560 | do_pos_format() const | |
561 | { return pattern(); } | |
562 | ||
563 | pattern | |
564 | do_neg_format() const | |
565 | { return pattern(); } | |
566 | }; | |
5e93f39f PR |
567 | } // namespace std |
568 | ||
569 | #endif // _GLIBCXX_TESTSUITE_CHARACTER_H | |
570 |