1 // Character Traits for use by standard string and iostream -*- C++ -*- 2 3 // Copyright (C) 1997-2018 Free Software Foundation, Inc. 4 // 5 // This file is part of the GNU ISO C++ Library. This library is free 6 // software; you can redistribute it and/or modify it under the 7 // terms of the GNU General Public License as published by the 8 // Free Software Foundation; either version 3, or (at your option) 9 // any later version. 10 11 // This library is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 16 // Under Section 7 of GPL version 3, you are granted additional 17 // permissions described in the GCC Runtime Library Exception, version 18 // 3.1, as published by the Free Software Foundation. 19 20 // You should have received a copy of the GNU General Public License and 21 // a copy of the GCC Runtime Library Exception along with this program; 22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 // <http://www.gnu.org/licenses/>. 24 25 /** @file bits/char_traits.h 26 * This is an internal header file, included by other library headers. 27 * Do not attempt to use it directly. @headername{string} 28 */ 29 30 // 31 // ISO C++ 14882: 21 Strings library 32 // 33 34 #ifndef _CHAR_TRAITS_H 35 #define _CHAR_TRAITS_H 1 36 37 #pragma GCC system_header 38 39 #include <bits/stl_algobase.h> // std::copy, std::fill_n 40 #include <bits/postypes.h> // For streampos 41 #include <cwchar> // For WEOF, wmemmove, wmemset, etc. 42 43 #ifndef _GLIBCXX_ALWAYS_INLINE 44 #define _GLIBCXX_ALWAYS_INLINE inline __attribute__((__always_inline__)) 45 #endif 46 47 namespace __gnu_cxx _GLIBCXX_VISIBILITY(default) 48 { 49 _GLIBCXX_BEGIN_NAMESPACE_VERSION 50 51 /** 52 * @brief Mapping from character type to associated types. 53 * 54 * @note This is an implementation class for the generic version 55 * of char_traits. It defines int_type, off_type, pos_type, and 56 * state_type. By default these are unsigned long, streamoff, 57 * streampos, and mbstate_t. Users who need a different set of 58 * types, but who don't need to change the definitions of any function 59 * defined in char_traits, can specialize __gnu_cxx::_Char_types 60 * while leaving __gnu_cxx::char_traits alone. */ 61 template<typename _CharT> 62 struct _Char_types 63 { 64 typedef unsigned long int_type; 65 typedef std::streampos pos_type; 66 typedef std::streamoff off_type; 67 typedef std::mbstate_t state_type; 68 }; 69 70 71 /** 72 * @brief Base class used to implement std::char_traits. 73 * 74 * @note For any given actual character type, this definition is 75 * probably wrong. (Most of the member functions are likely to be 76 * right, but the int_type and state_type typedefs, and the eof() 77 * member function, are likely to be wrong.) The reason this class 78 * exists is so users can specialize it. Classes in namespace std 79 * may not be specialized for fundamental types, but classes in 80 * namespace __gnu_cxx may be. 81 * 82 * See https://gcc.gnu.org/onlinedocs/libstdc++/manual/strings.html#strings.string.character_types 83 * for advice on how to make use of this class for @a unusual character 84 * types. Also, check out include/ext/pod_char_traits.h. 85 */ 86 template<typename _CharT> 87 struct char_traits 88 { 89 typedef _CharT char_type; 90 typedef typename _Char_types<_CharT>::int_type int_type; 91 typedef typename _Char_types<_CharT>::pos_type pos_type; 92 typedef typename _Char_types<_CharT>::off_type off_type; 93 typedef typename _Char_types<_CharT>::state_type state_type; 94 95 static _GLIBCXX14_CONSTEXPR void 96 assign(char_type& __c1, const char_type& __c2) 97 { __c1 = __c2; } 98 99 static _GLIBCXX_CONSTEXPR bool 100 eq(const char_type& __c1, const char_type& __c2) 101 { return __c1 == __c2; } 102 103 static _GLIBCXX_CONSTEXPR bool 104 lt(const char_type& __c1, const char_type& __c2) 105 { return __c1 < __c2; } 106 107 static _GLIBCXX14_CONSTEXPR int 108 compare(const char_type* __s1, const char_type* __s2, std::size_t __n); 109 110 static _GLIBCXX14_CONSTEXPR std::size_t 111 length(const char_type* __s); 112 113 static _GLIBCXX14_CONSTEXPR const char_type* 114 find(const char_type* __s, std::size_t __n, const char_type& __a); 115 116 static char_type* 117 move(char_type* __s1, const char_type* __s2, std::size_t __n); 118 119 static char_type* 120 copy(char_type* __s1, const char_type* __s2, std::size_t __n); 121 122 static char_type* 123 assign(char_type* __s, std::size_t __n, char_type __a); 124 125 static _GLIBCXX_CONSTEXPR char_type 126 to_char_type(const int_type& __c) 127 { return static_cast<char_type>(__c); } 128 129 static _GLIBCXX_CONSTEXPR int_type 130 to_int_type(const char_type& __c) 131 { return static_cast<int_type>(__c); } 132 133 static _GLIBCXX_CONSTEXPR bool 134 eq_int_type(const int_type& __c1, const int_type& __c2) 135 { return __c1 == __c2; } 136 137 static _GLIBCXX_CONSTEXPR int_type 138 eof() 139 { return static_cast<int_type>(_GLIBCXX_STDIO_EOF); } 140 141 static _GLIBCXX_CONSTEXPR int_type 142 not_eof(const int_type& __c) 143 { return !eq_int_type(__c, eof()) ? __c : to_int_type(char_type()); } 144 }; 145 146 template<typename _CharT> 147 _GLIBCXX14_CONSTEXPR int 148 char_traits<_CharT>:: 149 compare(const char_type* __s1, const char_type* __s2, std::size_t __n) 150 { 151 for (std::size_t __i = 0; __i < __n; ++__i) 152 if (lt(__s1[__i], __s2[__i])) 153 return -1; 154 else if (lt(__s2[__i], __s1[__i])) 155 return 1; 156 return 0; 157 } 158 159 template<typename _CharT> 160 _GLIBCXX14_CONSTEXPR std::size_t 161 char_traits<_CharT>:: 162 length(const char_type* __p) 163 { 164 std::size_t __i = 0; 165 while (!eq(__p[__i], char_type())) 166 ++__i; 167 return __i; 168 } 169 170 template<typename _CharT> 171 _GLIBCXX14_CONSTEXPR const typename char_traits<_CharT>::char_type* 172 char_traits<_CharT>:: 173 find(const char_type* __s, std::size_t __n, const char_type& __a) 174 { 175 for (std::size_t __i = 0; __i < __n; ++__i) 176 if (eq(__s[__i], __a)) 177 return __s + __i; 178 return 0; 179 } 180 181 template<typename _CharT> 182 typename char_traits<_CharT>::char_type* 183 char_traits<_CharT>:: 184 move(char_type* __s1, const char_type* __s2, std::size_t __n) 185 { 186 if (__n == 0) 187 return __s1; 188 return static_cast<_CharT*>(__builtin_memmove(__s1, __s2, 189 __n * sizeof(char_type))); 190 } 191 192 template<typename _CharT> 193 typename char_traits<_CharT>::char_type* 194 char_traits<_CharT>:: 195 copy(char_type* __s1, const char_type* __s2, std::size_t __n) 196 { 197 // NB: Inline std::copy so no recursive dependencies. 198 std::copy(__s2, __s2 + __n, __s1); 199 return __s1; 200 } 201 202 template<typename _CharT> 203 typename char_traits<_CharT>::char_type* 204 char_traits<_CharT>:: 205 assign(char_type* __s, std::size_t __n, char_type __a) 206 { 207 // NB: Inline std::fill_n so no recursive dependencies. 208 std::fill_n(__s, __n, __a); 209 return __s; 210 } 211 212 _GLIBCXX_END_NAMESPACE_VERSION 213 } // namespace 214 215 namespace std _GLIBCXX_VISIBILITY(default) 216 { 217 _GLIBCXX_BEGIN_NAMESPACE_VERSION 218 219 #if __cplusplus > 201402 220 #define __cpp_lib_constexpr_char_traits 201611 221 222 /** 223 * @brief Determine whether the characters of a NULL-terminated 224 * string are known at compile time. 225 * @param __s The string. 226 * 227 * Assumes that _CharT is a built-in character type. 228 */ 229 template<typename _CharT> 230 static _GLIBCXX_ALWAYS_INLINE constexpr bool 231 __constant_string_p(const _CharT* __s) 232 { 233 while (__builtin_constant_p(*__s) && *__s) 234 __s++; 235 return __builtin_constant_p(*__s); 236 } 237 238 /** 239 * @brief Determine whether the characters of a character array are 240 * known at compile time. 241 * @param __a The character array. 242 * @param __n Number of characters. 243 * 244 * Assumes that _CharT is a built-in character type. 245 */ 246 template<typename _CharT> 247 static _GLIBCXX_ALWAYS_INLINE constexpr bool 248 __constant_char_array_p(const _CharT* __a, size_t __n) 249 { 250 size_t __i = 0; 251 while (__i < __n && __builtin_constant_p(__a[__i])) 252 __i++; 253 return __i == __n; 254 } 255 #endif 256 257 // 21.1 258 /** 259 * @brief Basis for explicit traits specializations. 260 * 261 * @note For any given actual character type, this definition is 262 * probably wrong. Since this is just a thin wrapper around 263 * __gnu_cxx::char_traits, it is possible to achieve a more 264 * appropriate definition by specializing __gnu_cxx::char_traits. 265 * 266 * See https://gcc.gnu.org/onlinedocs/libstdc++/manual/strings.html#strings.string.character_types 267 * for advice on how to make use of this class for @a unusual character 268 * types. Also, check out include/ext/pod_char_traits.h. 269 */ 270 template<class _CharT> 271 struct char_traits : public __gnu_cxx::char_traits<_CharT> 272 { }; 273 274 275 /// 21.1.3.1 char_traits specializations 276 template<> 277 struct char_traits<char> 278 { 279 typedef char char_type; 280 typedef int int_type; 281 typedef streampos pos_type; 282 typedef streamoff off_type; 283 typedef mbstate_t state_type; 284 285 static _GLIBCXX17_CONSTEXPR void 286 assign(char_type& __c1, const char_type& __c2) _GLIBCXX_NOEXCEPT 287 { __c1 = __c2; } 288 289 static _GLIBCXX_CONSTEXPR bool 290 eq(const char_type& __c1, const char_type& __c2) _GLIBCXX_NOEXCEPT 291 { return __c1 == __c2; } 292 293 static _GLIBCXX_CONSTEXPR bool 294 lt(const char_type& __c1, const char_type& __c2) _GLIBCXX_NOEXCEPT 295 { 296 // LWG 467. 297 return (static_cast<unsigned char>(__c1) 298 < static_cast<unsigned char>(__c2)); 299 } 300 301 static _GLIBCXX17_CONSTEXPR int 302 compare(const char_type* __s1, const char_type* __s2, size_t __n) 303 { 304 #if __cplusplus > 201402 305 if (__builtin_constant_p(__n) 306 && __constant_char_array_p(__s1, __n) 307 && __constant_char_array_p(__s2, __n)) 308 return __gnu_cxx::char_traits<char_type>::compare(__s1, __s2, __n); 309 #endif 310 if (__n == 0) 311 return 0; 312 return __builtin_memcmp(__s1, __s2, __n); 313 } 314 315 static _GLIBCXX17_CONSTEXPR size_t 316 length(const char_type* __s) 317 { 318 #if __cplusplus > 201402 319 if (__constant_string_p(__s)) 320 return __gnu_cxx::char_traits<char_type>::length(__s); 321 #endif 322 return __builtin_strlen(__s); 323 } 324 325 static _GLIBCXX17_CONSTEXPR const char_type* 326 find(const char_type* __s, size_t __n, const char_type& __a) 327 { 328 #if __cplusplus > 201402 329 if (__builtin_constant_p(__n) 330 && __builtin_constant_p(__a) 331 && __constant_char_array_p(__s, __n)) 332 return __gnu_cxx::char_traits<char_type>::find(__s, __n, __a); 333 #endif 334 if (__n == 0) 335 return 0; 336 return static_cast<const char_type*>(__builtin_memchr(__s, __a, __n)); 337 } 338 339 static char_type* 340 move(char_type* __s1, const char_type* __s2, size_t __n) 341 { 342 if (__n == 0) 343 return __s1; 344 return static_cast<char_type*>(__builtin_memmove(__s1, __s2, __n)); 345 } 346 347 static char_type* 348 copy(char_type* __s1, const char_type* __s2, size_t __n) 349 { 350 if (__n == 0) 351 return __s1; 352 return static_cast<char_type*>(__builtin_memcpy(__s1, __s2, __n)); 353 } 354 355 static char_type* 356 assign(char_type* __s, size_t __n, char_type __a) 357 { 358 if (__n == 0) 359 return __s; 360 return static_cast<char_type*>(__builtin_memset(__s, __a, __n)); 361 } 362 363 static _GLIBCXX_CONSTEXPR char_type 364 to_char_type(const int_type& __c) _GLIBCXX_NOEXCEPT 365 { return static_cast<char_type>(__c); } 366 367 // To keep both the byte 0xff and the eof symbol 0xffffffff 368 // from ending up as 0xffffffff. 369 static _GLIBCXX_CONSTEXPR int_type 370 to_int_type(const char_type& __c) _GLIBCXX_NOEXCEPT 371 { return static_cast<int_type>(static_cast<unsigned char>(__c)); } 372 373 static _GLIBCXX_CONSTEXPR bool 374 eq_int_type(const int_type& __c1, const int_type& __c2) _GLIBCXX_NOEXCEPT 375 { return __c1 == __c2; } 376 377 static _GLIBCXX_CONSTEXPR int_type 378 eof() _GLIBCXX_NOEXCEPT 379 { return static_cast<int_type>(_GLIBCXX_STDIO_EOF); } 380 381 static _GLIBCXX_CONSTEXPR int_type 382 not_eof(const int_type& __c) _GLIBCXX_NOEXCEPT 383 { return (__c == eof()) ? 0 : __c; } 384 }; 385 386 387 #ifdef _GLIBCXX_USE_WCHAR_T 388 /// 21.1.3.2 char_traits specializations 389 template<> 390 struct char_traits<wchar_t> 391 { 392 typedef wchar_t char_type; 393 typedef wint_t int_type; 394 typedef streamoff off_type; 395 typedef wstreampos pos_type; 396 typedef mbstate_t state_type; 397 398 static _GLIBCXX17_CONSTEXPR void 399 assign(char_type& __c1, const char_type& __c2) _GLIBCXX_NOEXCEPT 400 { __c1 = __c2; } 401 402 static _GLIBCXX_CONSTEXPR bool 403 eq(const char_type& __c1, const char_type& __c2) _GLIBCXX_NOEXCEPT 404 { return __c1 == __c2; } 405 406 static _GLIBCXX_CONSTEXPR bool 407 lt(const char_type& __c1, const char_type& __c2) _GLIBCXX_NOEXCEPT 408 { return __c1 < __c2; } 409 410 static _GLIBCXX17_CONSTEXPR int 411 compare(const char_type* __s1, const char_type* __s2, size_t __n) 412 { 413 #if __cplusplus > 201402 414 if (__builtin_constant_p(__n) 415 && __constant_char_array_p(__s1, __n) 416 && __constant_char_array_p(__s2, __n)) 417 return __gnu_cxx::char_traits<char_type>::compare(__s1, __s2, __n); 418 #endif 419 if (__n == 0) 420 return 0; 421 else 422 return wmemcmp(__s1, __s2, __n); 423 } 424 425 static _GLIBCXX17_CONSTEXPR size_t 426 length(const char_type* __s) 427 { 428 #if __cplusplus > 201402 429 if (__constant_string_p(__s)) 430 return __gnu_cxx::char_traits<char_type>::length(__s); 431 else 432 #endif 433 return wcslen(__s); 434 } 435 436 static _GLIBCXX17_CONSTEXPR const char_type* 437 find(const char_type* __s, size_t __n, const char_type& __a) 438 { 439 #if __cplusplus > 201402 440 if (__builtin_constant_p(__n) 441 && __builtin_constant_p(__a) 442 && __constant_char_array_p(__s, __n)) 443 return __gnu_cxx::char_traits<char_type>::find(__s, __n, __a); 444 #endif 445 if (__n == 0) 446 return 0; 447 else 448 return wmemchr(__s, __a, __n); 449 } 450 451 static char_type* 452 move(char_type* __s1, const char_type* __s2, size_t __n) 453 { 454 if (__n == 0) 455 return __s1; 456 return wmemmove(__s1, __s2, __n); 457 } 458 459 static char_type* 460 copy(char_type* __s1, const char_type* __s2, size_t __n) 461 { 462 if (__n == 0) 463 return __s1; 464 return wmemcpy(__s1, __s2, __n); 465 } 466 467 static char_type* 468 assign(char_type* __s, size_t __n, char_type __a) 469 { 470 if (__n == 0) 471 return __s; 472 return wmemset(__s, __a, __n); 473 } 474 475 static _GLIBCXX_CONSTEXPR char_type 476 to_char_type(const int_type& __c) _GLIBCXX_NOEXCEPT 477 { return char_type(__c); } 478 479 static _GLIBCXX_CONSTEXPR int_type 480 to_int_type(const char_type& __c) _GLIBCXX_NOEXCEPT 481 { return int_type(__c); } 482 483 static _GLIBCXX_CONSTEXPR bool 484 eq_int_type(const int_type& __c1, const int_type& __c2) _GLIBCXX_NOEXCEPT 485 { return __c1 == __c2; } 486 487 static _GLIBCXX_CONSTEXPR int_type 488 eof() _GLIBCXX_NOEXCEPT 489 { return static_cast<int_type>(WEOF); } 490 491 static _GLIBCXX_CONSTEXPR int_type 492 not_eof(const int_type& __c) _GLIBCXX_NOEXCEPT 493 { return eq_int_type(__c, eof()) ? 0 : __c; } 494 }; 495 #endif //_GLIBCXX_USE_WCHAR_T 496 497 _GLIBCXX_END_NAMESPACE_VERSION 498 } // namespace 499 500 #if ((__cplusplus >= 201103L) \ 501 && defined(_GLIBCXX_USE_C99_STDINT_TR1)) 502 503 #include <cstdint> 504 505 namespace std _GLIBCXX_VISIBILITY(default) 506 { 507 _GLIBCXX_BEGIN_NAMESPACE_VERSION 508 509 template<> 510 struct char_traits<char16_t> 511 { 512 typedef char16_t char_type; 513 typedef uint_least16_t int_type; 514 typedef streamoff off_type; 515 typedef u16streampos pos_type; 516 typedef mbstate_t state_type; 517 518 static _GLIBCXX17_CONSTEXPR void 519 assign(char_type& __c1, const char_type& __c2) noexcept 520 { __c1 = __c2; } 521 522 static constexpr bool 523 eq(const char_type& __c1, const char_type& __c2) noexcept 524 { return __c1 == __c2; } 525 526 static constexpr bool 527 lt(const char_type& __c1, const char_type& __c2) noexcept 528 { return __c1 < __c2; } 529 530 static _GLIBCXX17_CONSTEXPR int 531 compare(const char_type* __s1, const char_type* __s2, size_t __n) 532 { 533 for (size_t __i = 0; __i < __n; ++__i) 534 if (lt(__s1[__i], __s2[__i])) 535 return -1; 536 else if (lt(__s2[__i], __s1[__i])) 537 return 1; 538 return 0; 539 } 540 541 static _GLIBCXX17_CONSTEXPR size_t 542 length(const char_type* __s) 543 { 544 size_t __i = 0; 545 while (!eq(__s[__i], char_type())) 546 ++__i; 547 return __i; 548 } 549 550 static _GLIBCXX17_CONSTEXPR const char_type* 551 find(const char_type* __s, size_t __n, const char_type& __a) 552 { 553 for (size_t __i = 0; __i < __n; ++__i) 554 if (eq(__s[__i], __a)) 555 return __s + __i; 556 return 0; 557 } 558 559 static char_type* 560 move(char_type* __s1, const char_type* __s2, size_t __n) 561 { 562 if (__n == 0) 563 return __s1; 564 return (static_cast<char_type*> 565 (__builtin_memmove(__s1, __s2, __n * sizeof(char_type)))); 566 } 567 568 static char_type* 569 copy(char_type* __s1, const char_type* __s2, size_t __n) 570 { 571 if (__n == 0) 572 return __s1; 573 return (static_cast<char_type*> 574 (__builtin_memcpy(__s1, __s2, __n * sizeof(char_type)))); 575 } 576 577 static char_type* 578 assign(char_type* __s, size_t __n, char_type __a) 579 { 580 for (size_t __i = 0; __i < __n; ++__i) 581 assign(__s[__i], __a); 582 return __s; 583 } 584 585 static constexpr char_type 586 to_char_type(const int_type& __c) noexcept 587 { return char_type(__c); } 588 589 static constexpr int_type 590 to_int_type(const char_type& __c) noexcept 591 { return __c == eof() ? int_type(0xfffd) : int_type(__c); } 592 593 static constexpr bool 594 eq_int_type(const int_type& __c1, const int_type& __c2) noexcept 595 { return __c1 == __c2; } 596 597 static constexpr int_type 598 eof() noexcept 599 { return static_cast<int_type>(-1); } 600 601 static constexpr int_type 602 not_eof(const int_type& __c) noexcept 603 { return eq_int_type(__c, eof()) ? 0 : __c; } 604 }; 605 606 template<> 607 struct char_traits<char32_t> 608 { 609 typedef char32_t char_type; 610 typedef uint_least32_t int_type; 611 typedef streamoff off_type; 612 typedef u32streampos pos_type; 613 typedef mbstate_t state_type; 614 615 static _GLIBCXX17_CONSTEXPR void 616 assign(char_type& __c1, const char_type& __c2) noexcept 617 { __c1 = __c2; } 618 619 static constexpr bool 620 eq(const char_type& __c1, const char_type& __c2) noexcept 621 { return __c1 == __c2; } 622 623 static constexpr bool 624 lt(const char_type& __c1, const char_type& __c2) noexcept 625 { return __c1 < __c2; } 626 627 static _GLIBCXX17_CONSTEXPR int 628 compare(const char_type* __s1, const char_type* __s2, size_t __n) 629 { 630 for (size_t __i = 0; __i < __n; ++__i) 631 if (lt(__s1[__i], __s2[__i])) 632 return -1; 633 else if (lt(__s2[__i], __s1[__i])) 634 return 1; 635 return 0; 636 } 637 638 static _GLIBCXX17_CONSTEXPR size_t 639 length(const char_type* __s) 640 { 641 size_t __i = 0; 642 while (!eq(__s[__i], char_type())) 643 ++__i; 644 return __i; 645 } 646 647 static _GLIBCXX17_CONSTEXPR const char_type* 648 find(const char_type* __s, size_t __n, const char_type& __a) 649 { 650 for (size_t __i = 0; __i < __n; ++__i) 651 if (eq(__s[__i], __a)) 652 return __s + __i; 653 return 0; 654 } 655 656 static char_type* 657 move(char_type* __s1, const char_type* __s2, size_t __n) 658 { 659 if (__n == 0) 660 return __s1; 661 return (static_cast<char_type*> 662 (__builtin_memmove(__s1, __s2, __n * sizeof(char_type)))); 663 } 664 665 static char_type* 666 copy(char_type* __s1, const char_type* __s2, size_t __n) 667 { 668 if (__n == 0) 669 return __s1; 670 return (static_cast<char_type*> 671 (__builtin_memcpy(__s1, __s2, __n * sizeof(char_type)))); 672 } 673 674 static char_type* 675 assign(char_type* __s, size_t __n, char_type __a) 676 { 677 for (size_t __i = 0; __i < __n; ++__i) 678 assign(__s[__i], __a); 679 return __s; 680 } 681 682 static constexpr char_type 683 to_char_type(const int_type& __c) noexcept 684 { return char_type(__c); } 685 686 static constexpr int_type 687 to_int_type(const char_type& __c) noexcept 688 { return int_type(__c); } 689 690 static constexpr bool 691 eq_int_type(const int_type& __c1, const int_type& __c2) noexcept 692 { return __c1 == __c2; } 693 694 static constexpr int_type 695 eof() noexcept 696 { return static_cast<int_type>(-1); } 697 698 static constexpr int_type 699 not_eof(const int_type& __c) noexcept 700 { return eq_int_type(__c, eof()) ? 0 : __c; } 701 }; 702 703 _GLIBCXX_END_NAMESPACE_VERSION 704 } // namespace 705 706 #endif 707 708 #endif // _CHAR_TRAITS_H 709