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-2023 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
     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
     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
     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
     139        __gnu_test::pod_uchar::char_type::to(const char_type& c)
     140        { return static_cast<V2>(c.value << 5); }
     141  } // namespace __gnu_cxx
     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  
     174        explicit codecvt(size_t refs = 0) : base_type(refs)
     175        { }
     176  
     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  	  {
     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
     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
     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
     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;
     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
     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:
     351        ~ctype()
     352        { }
     353  
     354        virtual bool
     355        do_is(mask, char_type) const
     356        { return false; }
     357  
     358        virtual const char_type*
     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*
     366        do_scan_is(mask, const char_type*, const char_type* high) const
     367        { return high; }
     368  
     369        virtual const char_type*
     370        do_scan_not(mask, const char_type* low, const char_type*) const
     371        { return low; }
     372  
     373        virtual char_type
     374        do_toupper(char_type c) const
     375        { return c; }
     376  
     377        virtual const char_type*
     378        do_toupper(char_type*, const char_type*  high) const
     379        { return high; }
     380  
     381        virtual char_type
     382        do_tolower(char_type c) const
     383        { return c; }
     384  
     385        virtual const char_type*
     386        do_tolower(char_type*, const char_type*  high) const
     387        { return high; }
     388  
     389        virtual char_type
     390        do_widen(char c) const
     391        { return __gnu_test::pod_uchar::from<char>(c); }
     392  
     393        virtual const char*
     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
     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
     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)
     426        : locale::facet(refs)
     427        { }
     428  
     429        char_type
     430        decimal_point() const
     431        { return this->do_decimal_point(); }
     432  
     433        char_type
     434        thousands_sep() const
     435        { return this->do_thousands_sep(); }
     436  
     437        string
     438        grouping() const
     439        { return this->do_grouping(); }
     440  
     441        string_type
     442        truename() const
     443        { return this->do_truename(); }
     444  
     445        string_type
     446        falsename() const
     447        { return this->do_falsename(); }
     448  
     449      protected:
     450        ~numpunct()
     451        { }
     452  
     453        virtual char_type
     454        do_decimal_point() const
     455        { return char_type(); }
     456  
     457        virtual char_type
     458        do_thousands_sep() const
     459        { return char_type(); }
     460  
     461        virtual string
     462        do_grouping() const
     463        { return string(); }
     464  
     465        virtual string_type
     466        do_truename() const
     467        { return string_type(); }
     468  
     469        virtual string_type
     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)
     487        : locale::facet(refs)
     488        { }
     489  
     490        char_type
     491        decimal_point() const
     492        { return this->do_decimal_point(); }
     493  
     494        char_type
     495        thousands_sep() const
     496        { return this->do_thousands_sep(); }
     497  
     498        string
     499        grouping() const
     500        { return this->do_grouping(); }
     501  
     502        string_type
     503        curr_symbol() const
     504        { return this->do_curr_symbol(); }
     505  
     506        string_type
     507        positive_sign() const
     508        { return this->do_positive_sign(); }
     509  
     510        string_type
     511        negative_sign() const
     512        { return this->do_negative_sign(); }
     513  
     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(); }
     521  
     522        pattern
     523        neg_format() const
     524        { return this->do_neg_format(); }
     525  
     526      protected:
     527        ~moneypunct()
     528        { }
     529  
     530        virtual char_type
     531        do_decimal_point() const
     532        { return char_type(); }
     533  
     534        virtual char_type
     535        do_thousands_sep() const
     536        { return char_type(); }
     537  
     538        virtual string
     539        do_grouping() const
     540        { return string(); }
     541  
     542        virtual string_type
     543        do_curr_symbol() const
     544        { return string_type(); }
     545  
     546        string_type
     547        do_positive_sign() const
     548        { return string_type(); }
     549  
     550        string_type
     551        do_negative_sign() const
     552        { return string_type(); }
     553  
     554        int
     555        do_frac_digits() const
     556        { return 0; }
     557  
     558        pattern
     559        do_pos_format() const
     560        { return pattern(); }
     561  
     562        pattern
     563        do_neg_format() const
     564        { return pattern(); }
     565      };
     566  } // namespace std
     567  
     568  #endif // _GLIBCXX_TESTSUITE_CHARACTER_H