1 // -*- C++ -*- 2 3 // Testing character type and state type with char_traits and codecvt 4 // specializations for the C++ library testsuite. 5 // 6 // Copyright (C) 2003-2013 Free Software Foundation, Inc. 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 11 // Free Software Foundation; either version 3, or (at your option) 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 20 // with this library; see the file COPYING3. If not see 21 // <http://www.gnu.org/licenses/>. 22 // 23 24 #ifndef _GLIBCXX_TESTSUITE_CHARACTER_H 25 #define _GLIBCXX_TESTSUITE_CHARACTER_H 26 27 #include <climits> 28 #include <string> // for char_traits 29 #include <locale> // for codecvt 30 #include <algorithm> // for transform 31 #include <ext/pod_char_traits.h> 32 33 namespace __gnu_test 34 { 35 struct pod_int 36 { 37 int value; 38 39 #if __cplusplus >= 201103L 40 // For std::iota. 41 pod_int& 42 operator++() 43 { 44 ++value; 45 return *this; 46 } 47 #endif 48 }; 49 50 // For 20.1 requirements for instantiable type: equality comparable 51 // and less than comparable. 52 inline bool 53 operator==(const pod_int& lhs, const pod_int& rhs) 54 { return lhs.value == rhs.value; } 55 56 inline bool 57 operator<(const pod_int& lhs, const pod_int& rhs) 58 { return lhs.value < rhs.value; } 59 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) 71 { 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) 78 { 79 pod_int ret = { lhs.value * rhs.value }; 80 return ret; 81 } 82 83 struct pod_state 84 { 85 unsigned long value; 86 }; 87 88 inline bool 89 operator==(const pod_state& lhs, const pod_state& rhs) 90 { return lhs.value == rhs.value; } 91 92 inline bool 93 operator<(const pod_state& lhs, const pod_state& rhs) 94 { return lhs.value < rhs.value; } 95 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; 101 typedef character<unsigned int, unsigned long> pod_uint; 102 } 103 104 namespace __gnu_cxx 105 { 106 // Specializations. 107 // pod_char 108 template<> 109 template<typename V2> 110 inline __gnu_test::pod_char::char_type from(const V2 & v)111 __gnu_test::pod_char::char_type::from(const V2& v) 112 { 113 char_type ret = { static_cast<value_type>(v.value) }; 114 return ret; 115 } 116 117 template<> 118 template<typename V2> 119 inline V2 to(const char_type & c)120 __gnu_test::pod_char::char_type::to(const char_type& c) 121 { 122 V2 ret = { c.value }; 123 return ret; 124 } 125 126 template<> 127 template<typename V2> 128 inline __gnu_test::pod_uchar::char_type from(const V2 & v)129 __gnu_test::pod_uchar::char_type::from(const V2& v) 130 { 131 char_type ret; 132 ret.value = (v >> 5); 133 return ret; 134 } 135 136 template<> 137 template<typename V2> 138 inline V2 to(const char_type & c)139 __gnu_test::pod_uchar::char_type::to(const char_type& c) 140 { return static_cast<V2>(c.value << 5); } 141 } // namespace __gnu_test 142 143 namespace std 144 { 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<> 162 class codecvt<__gnu_test::pod_uchar, char, __gnu_test::pod_state> 163 : public __codecvt_abstract_base<__gnu_test::pod_uchar, char, 164 __gnu_test::pod_state> 165 { 166 public: 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 base_type(refs)174 explicit codecvt(size_t refs = 0) : base_type(refs) 175 { } 176 177 static locale::id id; 178 179 protected: ~codecvt()180 ~codecvt() 181 { } 182 183 virtual result do_out(state_type & state,const intern_type * from,const intern_type * from_end,const intern_type * & from_next,extern_type * to,extern_type * to_limit,extern_type * & to_next)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 { 191 unsigned char tmp = (state.value ^ from->value); 192 if (state.value & 0x8) 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 } 207 state.value = tmp; 208 ++from; 209 } 210 211 from_next = from; 212 to_next = to; 213 return (from < from_end) ? partial : ok; 214 } 215 216 virtual result do_in(state_type & state,const extern_type * from,const extern_type * from_end,const extern_type * & from_next,intern_type * to,intern_type * to_limit,intern_type * & to_next)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 228 state.value &= c; 229 ++from; 230 continue; 231 } 232 233 unsigned char tmp; 234 if (state.value & 0x8) 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 } 249 to->value = (tmp ^ state.value); 250 state.value = tmp; 251 ++to; 252 } 253 254 from_next = from; 255 to_next = to; 256 return (from < from_end) ? partial : ok; 257 } 258 259 virtual result do_unshift(state_type & state,extern_type * to,extern_type * to_limit,extern_type * & to_next)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); 266 if (state.value & mask) 267 { 268 if (to == to_limit) 269 { 270 to_next = to; 271 return partial; 272 } 273 274 state.value &= ~mask; 275 *to++ = static_cast<unsigned char>(~mask); 276 } 277 } 278 279 to_next = to; 280 return state.value == 0 ? ok : error; 281 } 282 283 virtual int do_encoding()284 do_encoding() const throw() 285 { return -1; } 286 287 virtual bool do_always_noconv()288 do_always_noconv() const throw() 289 { return false; } 290 291 virtual int do_length(state_type & state,const extern_type * from,const extern_type * end,size_t max)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; 296 while (from < end) 297 { 298 unsigned char c = *from; 299 if (c & 0xc0) 300 { 301 // Unshift sequence 302 state.value &= c; 303 ++from; 304 continue; 305 } 306 307 if (max == 0) break; 308 309 unsigned char tmp; 310 if (state.value & 0x8) 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 } 325 state.value = tmp; 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 do_max_length()334 do_max_length() const throw() 335 { return 11; } 336 }; 337 338 template<> 339 class ctype<__gnu_test::pod_uchar> 340 : public __ctype_abstract_base<__gnu_test::pod_uchar> 341 { 342 public: 343 typedef __gnu_test::pod_uchar char_type; 344 345 explicit ctype(size_t refs = 0) 346 : __ctype_abstract_base<__gnu_test::pod_uchar>(refs) { } 347 348 static locale::id id; 349 350 protected: ~ctype()351 ~ctype() 352 { } 353 354 virtual bool do_is(mask,char_type)355 do_is(mask, char_type) const 356 { return false; } 357 358 virtual const char_type* do_is(const char_type * low,const char_type * high,mask * vec)359 do_is(const char_type* low, const char_type* high, mask* vec) const 360 { 361 fill_n(vec, high - low, mask()); 362 return high; 363 } 364 365 virtual const char_type* do_scan_is(mask,const char_type *,const char_type * high)366 do_scan_is(mask, const char_type*, const char_type* high) const 367 { return high; } 368 369 virtual const char_type* do_scan_not(mask,const char_type * low,const char_type *)370 do_scan_not(mask, const char_type* low, const char_type*) const 371 { return low; } 372 373 virtual char_type do_toupper(char_type c)374 do_toupper(char_type c) const 375 { return c; } 376 377 virtual const char_type* do_toupper(char_type *,const char_type * high)378 do_toupper(char_type*, const char_type* high) const 379 { return high; } 380 381 virtual char_type do_tolower(char_type c)382 do_tolower(char_type c) const 383 { return c; } 384 385 virtual const char_type* do_tolower(char_type *,const char_type * high)386 do_tolower(char_type*, const char_type* high) const 387 { return high; } 388 389 virtual char_type do_widen(char c)390 do_widen(char c) const 391 { return __gnu_test::pod_uchar::from<char>(c); } 392 393 virtual const char* do_widen(const char * low,const char * high,char_type * dest)394 do_widen(const char* low, const char* high, char_type* dest) const 395 { 396 transform(low, high, dest, &__gnu_test::pod_uchar::from<char>); 397 return high; 398 } 399 400 virtual char do_narrow(char_type,char dfault)401 do_narrow(char_type, char dfault) const 402 { return dfault; } 403 404 virtual const char_type* do_narrow(const char_type * low,const char_type * high,char dfault,char * dest)405 do_narrow(const char_type* low, const char_type* high, 406 char dfault, char* dest) const 407 { 408 fill_n(dest, high - low, dfault); 409 return high; 410 } 411 }; 412 413 // numpunct specializations 414 template<> 415 class numpunct<__gnu_test::pod_uint> 416 : public locale::facet 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 424 explicit 425 numpunct(size_t refs = 0) facet(refs)426 : locale::facet(refs) 427 { } 428 429 char_type decimal_point()430 decimal_point() const 431 { return this->do_decimal_point(); } 432 433 char_type thousands_sep()434 thousands_sep() const 435 { return this->do_thousands_sep(); } 436 437 string grouping()438 grouping() const 439 { return this->do_grouping(); } 440 441 string_type truename()442 truename() const 443 { return this->do_truename(); } 444 445 string_type falsename()446 falsename() const 447 { return this->do_falsename(); } 448 449 protected: ~numpunct()450 ~numpunct() 451 { } 452 453 virtual char_type do_decimal_point()454 do_decimal_point() const 455 { return char_type(); } 456 457 virtual char_type do_thousands_sep()458 do_thousands_sep() const 459 { return char_type(); } 460 461 virtual string do_grouping()462 do_grouping() const 463 { return string(); } 464 465 virtual string_type do_truename()466 do_truename() const 467 { return string_type(); } 468 469 virtual string_type do_falsename()470 do_falsename() const 471 { return string_type(); } 472 }; 473 474 template<> 475 class moneypunct<__gnu_test::pod_uint> 476 : public locale::facet, public money_base 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; 483 static const bool intl = false; 484 485 explicit 486 moneypunct(size_t refs = 0) facet(refs)487 : locale::facet(refs) 488 { } 489 490 char_type decimal_point()491 decimal_point() const 492 { return this->do_decimal_point(); } 493 494 char_type thousands_sep()495 thousands_sep() const 496 { return this->do_thousands_sep(); } 497 498 string grouping()499 grouping() const 500 { return this->do_grouping(); } 501 502 string_type curr_symbol()503 curr_symbol() const 504 { return this->do_curr_symbol(); } 505 506 string_type positive_sign()507 positive_sign() const 508 { return this->do_positive_sign(); } 509 510 string_type negative_sign()511 negative_sign() const 512 { return this->do_negative_sign(); } 513 514 int frac_digits()515 frac_digits() const 516 { return this->do_frac_digits(); } 517 518 pattern pos_format()519 pos_format() const 520 { return this->do_pos_format(); } 521 522 pattern neg_format()523 neg_format() const 524 { return this->do_neg_format(); } 525 526 protected: ~moneypunct()527 ~moneypunct() 528 { } 529 530 virtual char_type do_decimal_point()531 do_decimal_point() const 532 { return char_type(); } 533 534 virtual char_type do_thousands_sep()535 do_thousands_sep() const 536 { return char_type(); } 537 538 virtual string do_grouping()539 do_grouping() const 540 { return string(); } 541 542 virtual string_type do_curr_symbol()543 do_curr_symbol() const 544 { return string_type(); } 545 546 string_type do_positive_sign()547 do_positive_sign() const 548 { return string_type(); } 549 550 string_type do_negative_sign()551 do_negative_sign() const 552 { return string_type(); } 553 554 int do_frac_digits()555 do_frac_digits() const 556 { return 0; } 557 558 pattern do_pos_format()559 do_pos_format() const 560 { return pattern(); } 561 562 pattern do_neg_format()563 do_neg_format() const 564 { return pattern(); } 565 }; 566 } // namespace std 567 568 #endif // _GLIBCXX_TESTSUITE_CHARACTER_H 569 570