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