// -*- C++ -*- // Testing character type and state type with char_traits and codecvt // specializations for the C++ library testsuite. // // Copyright (C) 2003-2019 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 // . // #ifndef _GLIBCXX_TESTSUITE_CHARACTER_H #define _GLIBCXX_TESTSUITE_CHARACTER_H #include #include // for char_traits #include // for codecvt #include // for transform #include 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 pod_char; typedef character pod_uchar; typedef character pod_ushort; typedef character pod_uint; } namespace __gnu_cxx { // Specializations. // pod_char template<> template inline __gnu_test::pod_char::char_type __gnu_test::pod_char::char_type::from(const V2& v) { char_type ret = { static_cast(v.value) }; return ret; } template<> template inline V2 __gnu_test::pod_char::char_type::to(const char_type& c) { V2 ret = { c.value }; return ret; } template<> template 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 inline V2 __gnu_test::pod_uchar::char_type::to(const char_type& c) { return static_cast(c.value << 5); } } // namespace __gnu_test 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 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(~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(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); 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 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 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