|  | // -*- C++ -*- | 
|  |  | 
|  | // Testing character type and state type with char_traits and codecvt | 
|  | // specializations for the C++ library testsuite. | 
|  | // | 
|  | // Copyright (C) 2003-2025 Free Software Foundation, Inc. | 
|  | // | 
|  | // This file is part of the GNU ISO C++ Library.  This library is free | 
|  | // software; you can redistribute it and/or modify it under the | 
|  | // terms of the GNU General Public License as published by the | 
|  | // Free Software Foundation; either version 3, or (at your option) | 
|  | // any later version. | 
|  | // | 
|  | // This library is distributed in the hope that it will be useful, | 
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | // GNU General Public License for more details. | 
|  | // | 
|  | // You should have received a copy of the GNU General Public License along | 
|  | // with this library; see the file COPYING3.  If not see | 
|  | // <http://www.gnu.org/licenses/>. | 
|  | // | 
|  |  | 
|  | #ifndef _GLIBCXX_TESTSUITE_CHARACTER_H | 
|  | #define _GLIBCXX_TESTSUITE_CHARACTER_H | 
|  |  | 
|  | #include <climits> | 
|  | #include <string> // for char_traits | 
|  | #include <locale> // for codecvt | 
|  | #include <algorithm> // for transform | 
|  | #include <ext/pod_char_traits.h> | 
|  |  | 
|  | namespace __gnu_test | 
|  | { | 
|  | struct pod_int | 
|  | { | 
|  | int value; | 
|  |  | 
|  | #if __cplusplus >= 201103L | 
|  | // For std::iota. | 
|  | pod_int& | 
|  | operator++() | 
|  | { | 
|  | ++value; | 
|  | return *this; | 
|  | } | 
|  | #endif | 
|  | }; | 
|  |  | 
|  | // For 20.1 requirements for instantiable type: equality comparable | 
|  | // and less than comparable. | 
|  | inline bool | 
|  | operator==(const pod_int& lhs, const pod_int& rhs) | 
|  | { return lhs.value == rhs.value; } | 
|  |  | 
|  | inline bool | 
|  | operator<(const pod_int& lhs, const pod_int& rhs) | 
|  | { return lhs.value < rhs.value; } | 
|  |  | 
|  | // For 26 numeric algorithms requirements, need addable, | 
|  | // subtractable, multiplicable. | 
|  | inline pod_int | 
|  | operator+(const pod_int& lhs, const pod_int& rhs) | 
|  | { | 
|  | pod_int ret = { lhs.value + rhs.value }; | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | inline pod_int | 
|  | operator-(const pod_int& lhs, const pod_int& rhs) | 
|  | { | 
|  | pod_int ret = { lhs.value - rhs.value }; | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | inline pod_int | 
|  | operator*(const pod_int& lhs, const pod_int& rhs) | 
|  | { | 
|  | pod_int ret = { lhs.value * rhs.value }; | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | struct pod_state | 
|  | { | 
|  | unsigned long value; | 
|  | }; | 
|  |  | 
|  | inline bool | 
|  | operator==(const pod_state& lhs, const pod_state& rhs) | 
|  | { return lhs.value == rhs.value; } | 
|  |  | 
|  | inline bool | 
|  | operator<(const pod_state& lhs, const pod_state& rhs) | 
|  | { return lhs.value < rhs.value; } | 
|  |  | 
|  | // Alternate character types. | 
|  | using __gnu_cxx::character; | 
|  | typedef character<unsigned char, pod_int, pod_state>  	pod_char; | 
|  | typedef character<unsigned char, unsigned int, pod_state>  	pod_uchar; | 
|  | typedef character<unsigned short, unsigned int>	   	pod_ushort; | 
|  | typedef character<unsigned int, unsigned long>	   	pod_uint; | 
|  | } | 
|  |  | 
|  | namespace __gnu_cxx | 
|  | { | 
|  | // Specializations. | 
|  | // pod_char | 
|  | template<> | 
|  | template<typename V2> | 
|  | inline __gnu_test::pod_char::char_type | 
|  | __gnu_test::pod_char::char_type::from(const V2& v) | 
|  | { | 
|  | char_type ret = { static_cast<value_type>(v.value) }; | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | template<> | 
|  | template<typename V2> | 
|  | inline V2 | 
|  | __gnu_test::pod_char::char_type::to(const char_type& c) | 
|  | { | 
|  | V2 ret = { c.value }; | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | template<> | 
|  | template<typename V2> | 
|  | inline __gnu_test::pod_uchar::char_type | 
|  | __gnu_test::pod_uchar::char_type::from(const V2& v) | 
|  | { | 
|  | char_type ret; | 
|  | ret.value = (v >> 5); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | template<> | 
|  | template<typename V2> | 
|  | inline V2 | 
|  | __gnu_test::pod_uchar::char_type::to(const char_type& c) | 
|  | { return static_cast<V2>(c.value << 5); } | 
|  | } // namespace __gnu_cxx | 
|  |  | 
|  | namespace std | 
|  | { | 
|  | // codecvt specialization | 
|  | // | 
|  | // The conversion performed by the specialization is not supposed to | 
|  | // be useful, rather it has been designed to demonstrate the | 
|  | // essential features of stateful conversions: | 
|  | // * Number and value of bytes for each internal character depends on the | 
|  | //   state in addition to the character itself. | 
|  | // * Unshift produces an unshift sequence and resets the state. On input | 
|  | //   the unshift sequence causes the state to be reset. | 
|  | // | 
|  | // The conversion for output is as follows: | 
|  | // 1. Calculate the value tmp by xor-ing the state and the internal | 
|  | //    character | 
|  | // 2. Split tmp into either two or three bytes depending on the value of | 
|  | //    state. Output those bytes. | 
|  | // 3. tmp becomes the new value of state. | 
|  | template<> | 
|  | class codecvt<__gnu_test::pod_uchar, char, __gnu_test::pod_state> | 
|  | : public __codecvt_abstract_base<__gnu_test::pod_uchar, char, | 
|  | __gnu_test::pod_state> | 
|  | { | 
|  | public: | 
|  | typedef codecvt_base::result	result; | 
|  | typedef __gnu_test::pod_uchar 	intern_type; | 
|  | typedef char 			extern_type; | 
|  | typedef __gnu_test::pod_state 	state_type; | 
|  | typedef __codecvt_abstract_base<intern_type, extern_type, state_type> | 
|  | base_type; | 
|  |  | 
|  | explicit codecvt(size_t refs = 0) : base_type(refs) | 
|  | { } | 
|  |  | 
|  | static locale::id id; | 
|  |  | 
|  | protected: | 
|  | ~codecvt() | 
|  | { } | 
|  |  | 
|  | 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) const | 
|  | { | 
|  | while (from < from_end && to < to_limit) | 
|  | { | 
|  | unsigned char tmp = (state.value ^ from->value); | 
|  | if (state.value & 0x8) | 
|  | { | 
|  | if (to >= to_limit - 2) | 
|  | break; | 
|  | *to++ = (tmp & 0x7); | 
|  | *to++ = ((tmp >> 3) & 0x7); | 
|  | *to++ = ((tmp >> 6) & 0x3); | 
|  | } | 
|  | else | 
|  | { | 
|  | if (to >= to_limit - 1) | 
|  | break; | 
|  | *to++ = (tmp & 0xf); | 
|  | *to++ = ((tmp >> 4) & 0xf); | 
|  | } | 
|  | state.value = tmp; | 
|  | ++from; | 
|  | } | 
|  |  | 
|  | from_next = from; | 
|  | to_next = to; | 
|  | return (from < from_end) ? partial : ok; | 
|  | } | 
|  |  | 
|  | 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) const | 
|  | { | 
|  | while (from < from_end && to < to_limit) | 
|  | { | 
|  | unsigned char c = *from; | 
|  | if (c & 0xc0) | 
|  | { | 
|  | // Unshift sequence | 
|  | state.value &= c; | 
|  | ++from; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | unsigned char tmp; | 
|  | if (state.value & 0x8) | 
|  | { | 
|  | if (from >= from_end - 2) | 
|  | break; | 
|  | tmp = (*from++ & 0x7); | 
|  | tmp |= ((*from++ << 3) & 0x38); | 
|  | tmp |= ((*from++ << 6) & 0xc0); | 
|  | } | 
|  | else | 
|  | { | 
|  | if (from >= from_end - 1) | 
|  | break; | 
|  | tmp = (*from++ & 0xf); | 
|  | tmp |= ((*from++ << 4) & 0xf0); | 
|  | } | 
|  | to->value = (tmp ^ state.value); | 
|  | state.value = tmp; | 
|  | ++to; | 
|  | } | 
|  |  | 
|  | from_next = from; | 
|  | to_next = to; | 
|  | return (from < from_end) ? partial : ok; | 
|  | } | 
|  |  | 
|  | virtual result | 
|  | do_unshift(state_type& state, extern_type* to, extern_type* to_limit, | 
|  | extern_type*& to_next) const | 
|  | { | 
|  | for (unsigned int i = 0; i < CHAR_BIT; ++i) | 
|  | { | 
|  | unsigned int mask = (1 << i); | 
|  | if (state.value & mask) | 
|  | { | 
|  | if (to == to_limit) | 
|  | { | 
|  | to_next = to; | 
|  | return partial; | 
|  | } | 
|  |  | 
|  | state.value &= ~mask; | 
|  | *to++ = static_cast<unsigned char>(~mask); | 
|  | } | 
|  | } | 
|  |  | 
|  | to_next = to; | 
|  | return state.value == 0 ? ok : error; | 
|  | } | 
|  |  | 
|  | virtual int | 
|  | do_encoding() const throw() | 
|  | { return -1; } | 
|  |  | 
|  | virtual bool | 
|  | do_always_noconv() const throw() | 
|  | { return false; } | 
|  |  | 
|  | virtual int | 
|  | do_length(state_type& state, const extern_type* from, | 
|  | const extern_type* end, size_t max) const | 
|  | { | 
|  | const extern_type* beg = from; | 
|  | while (from < end) | 
|  | { | 
|  | unsigned char c = *from; | 
|  | if (c & 0xc0) | 
|  | { | 
|  | // Unshift sequence | 
|  | state.value &= c; | 
|  | ++from; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (max == 0) break; | 
|  |  | 
|  | unsigned char tmp; | 
|  | if (state.value & 0x8) | 
|  | { | 
|  | if (from >= end - 2) | 
|  | break; | 
|  | tmp = (*from++ & 0x7); | 
|  | tmp |= ((*from++ << 3) & 0x38); | 
|  | tmp |= ((*from++ << 6) & 0xc0); | 
|  | } | 
|  | else | 
|  | { | 
|  | if (from >= end - 1) | 
|  | break; | 
|  | tmp = (*from++ & 0xf); | 
|  | tmp |= ((*from++ << 4) & 0xf0); | 
|  | } | 
|  | state.value = tmp; | 
|  | --max; | 
|  | } | 
|  | return from - beg; | 
|  | } | 
|  |  | 
|  | // Maximum 8 bytes unshift sequence followed by max 3 bytes for | 
|  | // one character. | 
|  | virtual int | 
|  | do_max_length() const throw() | 
|  | { return 11; } | 
|  | }; | 
|  |  | 
|  | template<> | 
|  | class ctype<__gnu_test::pod_uchar> | 
|  | : public __ctype_abstract_base<__gnu_test::pod_uchar> | 
|  | { | 
|  | public: | 
|  | typedef __gnu_test::pod_uchar char_type; | 
|  |  | 
|  | explicit ctype(size_t refs  = 0) | 
|  | : __ctype_abstract_base<__gnu_test::pod_uchar>(refs) { } | 
|  |  | 
|  | static locale::id id; | 
|  |  | 
|  | protected: | 
|  | ~ctype() | 
|  | { } | 
|  |  | 
|  | virtual bool | 
|  | do_is(mask, char_type) const | 
|  | { return false; } | 
|  |  | 
|  | virtual const char_type* | 
|  | do_is(const char_type* low, const char_type* high, mask* vec) const | 
|  | { | 
|  | fill_n(vec, high - low, mask()); | 
|  | return high; | 
|  | } | 
|  |  | 
|  | virtual const char_type* | 
|  | do_scan_is(mask, const char_type*, const char_type* high) const | 
|  | { return high; } | 
|  |  | 
|  | virtual const char_type* | 
|  | do_scan_not(mask, const char_type* low, const char_type*) const | 
|  | { return low; } | 
|  |  | 
|  | virtual char_type | 
|  | do_toupper(char_type c) const | 
|  | { return c; } | 
|  |  | 
|  | virtual const char_type* | 
|  | do_toupper(char_type*, const char_type*  high) const | 
|  | { return high; } | 
|  |  | 
|  | virtual char_type | 
|  | do_tolower(char_type c) const | 
|  | { return c; } | 
|  |  | 
|  | virtual const char_type* | 
|  | do_tolower(char_type*, const char_type*  high) const | 
|  | { return high; } | 
|  |  | 
|  | virtual char_type | 
|  | do_widen(char c) const | 
|  | { return __gnu_test::pod_uchar::from<char>(c); } | 
|  |  | 
|  | virtual const char* | 
|  | do_widen(const char* low, const char* high, char_type* dest) const | 
|  | { | 
|  | transform(low, high, dest, &__gnu_test::pod_uchar::from<char>); | 
|  | return high; | 
|  | } | 
|  |  | 
|  | virtual char | 
|  | do_narrow(char_type, char dfault) const | 
|  | { return dfault; } | 
|  |  | 
|  | virtual const char_type* | 
|  | do_narrow(const char_type* low, const char_type* high, | 
|  | char dfault, char*  dest) const | 
|  | { | 
|  | fill_n(dest, high - low, dfault); | 
|  | return high; | 
|  | } | 
|  | }; | 
|  |  | 
|  | // numpunct specializations | 
|  | template<> | 
|  | class numpunct<__gnu_test::pod_uint> | 
|  | : public locale::facet | 
|  | { | 
|  | public: | 
|  | typedef __gnu_test::pod_uint    char_type; | 
|  | typedef basic_string<char_type> string_type; | 
|  |  | 
|  | static locale::id id; | 
|  |  | 
|  | explicit | 
|  | numpunct(size_t refs = 0) | 
|  | : locale::facet(refs) | 
|  | { } | 
|  |  | 
|  | char_type | 
|  | decimal_point() const | 
|  | { return this->do_decimal_point(); } | 
|  |  | 
|  | char_type | 
|  | thousands_sep() const | 
|  | { return this->do_thousands_sep(); } | 
|  |  | 
|  | string | 
|  | grouping() const | 
|  | { return this->do_grouping(); } | 
|  |  | 
|  | string_type | 
|  | truename() const | 
|  | { return this->do_truename(); } | 
|  |  | 
|  | string_type | 
|  | falsename() const | 
|  | { return this->do_falsename(); } | 
|  |  | 
|  | protected: | 
|  | ~numpunct() | 
|  | { } | 
|  |  | 
|  | virtual char_type | 
|  | do_decimal_point() const | 
|  | { return char_type(); } | 
|  |  | 
|  | virtual char_type | 
|  | do_thousands_sep() const | 
|  | { return char_type(); } | 
|  |  | 
|  | virtual string | 
|  | do_grouping() const | 
|  | { return string(); } | 
|  |  | 
|  | virtual string_type | 
|  | do_truename() const | 
|  | { return string_type(); } | 
|  |  | 
|  | virtual string_type | 
|  | do_falsename() const | 
|  | { return string_type(); } | 
|  | }; | 
|  |  | 
|  | template<> | 
|  | class moneypunct<__gnu_test::pod_uint> | 
|  | : public locale::facet, public money_base | 
|  | { | 
|  | public: | 
|  | typedef __gnu_test::pod_uint    char_type; | 
|  | typedef basic_string<char_type> string_type; | 
|  |  | 
|  | static locale::id id; | 
|  | static const bool intl = false; | 
|  |  | 
|  | explicit | 
|  | moneypunct(size_t refs = 0) | 
|  | : locale::facet(refs) | 
|  | { } | 
|  |  | 
|  | char_type | 
|  | decimal_point() const | 
|  | { return this->do_decimal_point(); } | 
|  |  | 
|  | char_type | 
|  | thousands_sep() const | 
|  | { return this->do_thousands_sep(); } | 
|  |  | 
|  | string | 
|  | grouping() const | 
|  | { return this->do_grouping(); } | 
|  |  | 
|  | string_type | 
|  | curr_symbol() const | 
|  | { return this->do_curr_symbol(); } | 
|  |  | 
|  | string_type | 
|  | positive_sign() const | 
|  | { return this->do_positive_sign(); } | 
|  |  | 
|  | string_type | 
|  | negative_sign() const | 
|  | { return this->do_negative_sign(); } | 
|  |  | 
|  | int | 
|  | frac_digits() const | 
|  | { return this->do_frac_digits(); } | 
|  |  | 
|  | pattern | 
|  | pos_format() const | 
|  | { return this->do_pos_format(); } | 
|  |  | 
|  | pattern | 
|  | neg_format() const | 
|  | { return this->do_neg_format(); } | 
|  |  | 
|  | protected: | 
|  | ~moneypunct() | 
|  | { } | 
|  |  | 
|  | virtual char_type | 
|  | do_decimal_point() const | 
|  | { return char_type(); } | 
|  |  | 
|  | virtual char_type | 
|  | do_thousands_sep() const | 
|  | { return char_type(); } | 
|  |  | 
|  | virtual string | 
|  | do_grouping() const | 
|  | { return string(); } | 
|  |  | 
|  | virtual string_type | 
|  | do_curr_symbol() const | 
|  | { return string_type(); } | 
|  |  | 
|  | string_type | 
|  | do_positive_sign() const | 
|  | { return string_type(); } | 
|  |  | 
|  | string_type | 
|  | do_negative_sign() const | 
|  | { return string_type(); } | 
|  |  | 
|  | int | 
|  | do_frac_digits() const | 
|  | { return 0; } | 
|  |  | 
|  | pattern | 
|  | do_pos_format() const | 
|  | { return pattern(); } | 
|  |  | 
|  | pattern | 
|  | do_neg_format() const | 
|  | { return pattern(); } | 
|  | }; | 
|  | } // namespace std | 
|  |  | 
|  | #endif // _GLIBCXX_TESTSUITE_CHARACTER_H |