118334Speter// -*- C++ -*-
290075Sobrien
318334Speter// Testing character type and state type with char_traits and codecvt
418334Speter// specializations for the C++ library testsuite.
518334Speter//
618334Speter// Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009
718334Speter// Free Software Foundation, Inc.
818334Speter//
918334Speter// This file is part of the GNU ISO C++ Library.  This library is free
1018334Speter// software; you can redistribute it and/or modify it under the
1118334Speter// terms of the GNU General Public License as published by the
1218334Speter// Free Software Foundation; either version 3, or (at your option)
1318334Speter// any later version.
1418334Speter//
1518334Speter// This library is distributed in the hope that it will be useful,
1618334Speter// but WITHOUT ANY WARRANTY; without even the implied warranty of
1718334Speter// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1818334Speter// GNU General Public License for more details.
1918334Speter//
2018334Speter// You should have received a copy of the GNU General Public License along
2118334Speter// with this library; see the file COPYING3.  If not see
2218334Speter// <http://www.gnu.org/licenses/>.
2318334Speter//
2418334Speter
2518334Speter#ifndef _GLIBCXX_TESTSUITE_CHARACTER_H
2618334Speter#define _GLIBCXX_TESTSUITE_CHARACTER_H
2718334Speter
2818334Speter#include <climits>
2918334Speter#include <string> // for char_traits
3018334Speter#include <locale> // for codecvt
3118334Speter#include <algorithm> // for transform
3290075Sobrien#include <ext/pod_char_traits.h>
3390075Sobrien
3418334Speternamespace __gnu_test
3518334Speter{
3618334Speter  struct pod_int
3718334Speter  {
3818334Speter    int value;
3990075Sobrien
4018334Speter#ifdef __GXX_EXPERIMENTAL_CXX0X__
4118334Speter    // For std::iota.
4218334Speter    pod_int&
4318334Speter    operator++()
4418334Speter    {
4518334Speter      ++value;
4618334Speter      return *this;
4718334Speter    }
4818334Speter#endif
4918334Speter  };
5018334Speter
5118334Speter  // For 20.1 requirements for instantiable type: equality comparable
5290075Sobrien  // and less than comparable.
5318334Speter  inline bool
5418334Speter  operator==(const pod_int& lhs, const pod_int& rhs)
5518334Speter  { return lhs.value == rhs.value; }
5618334Speter
5718334Speter  inline bool
5818334Speter  operator<(const pod_int& lhs, const pod_int& rhs)
5918334Speter  { return lhs.value < rhs.value; }
6018334Speter
6118334Speter  // For 26 numeric algorithms requirements, need addable,
6218334Speter  // subtractable, multiplicable.
6318334Speter  inline pod_int
6418334Speter  operator+(const pod_int& lhs, const pod_int& rhs)
6590075Sobrien  {
6690075Sobrien    pod_int ret = { lhs.value + rhs.value };
6790075Sobrien    return ret;
6818334Speter  }
6918334Speter
7018334Speter  inline pod_int
7190075Sobrien  operator-(const pod_int& lhs, const pod_int& rhs)
7218334Speter  {
7318334Speter    pod_int ret = { lhs.value - rhs.value };
7418334Speter    return ret;
7518334Speter  }
7618334Speter
7718334Speter  inline pod_int
7818334Speter  operator*(const pod_int& lhs, const pod_int& rhs)
7990075Sobrien  {
8018334Speter    pod_int ret = { lhs.value * rhs.value };
8118334Speter    return ret;
8218334Speter  }
8318334Speter
8418334Speter  struct pod_state
8518334Speter  {
8618334Speter    unsigned long value;
8718334Speter  };
8818334Speter
8918334Speter  inline bool
9018334Speter  operator==(const pod_state& lhs, const pod_state& rhs)
9118334Speter  { return lhs.value == rhs.value; }
9218334Speter
9318334Speter  inline bool
9418334Speter  operator<(const pod_state& lhs, const pod_state& rhs)
9518334Speter  { return lhs.value < rhs.value; }
9618334Speter
9718334Speter  // Alternate character types.
9818334Speter  using __gnu_cxx::character;
9918334Speter  typedef character<unsigned char, pod_int, pod_state>  	pod_char;
10018334Speter  typedef character<unsigned char, unsigned int, pod_state>  	pod_uchar;
10118334Speter  typedef character<unsigned short, unsigned int>	   	pod_ushort;
10218334Speter  typedef character<unsigned int, unsigned long>	   	pod_uint;
10318334Speter}
10450397Sobrien
10550397Sobriennamespace __gnu_cxx
10650397Sobrien{
10750397Sobrien  // Specializations.
10850397Sobrien  // pod_char
10950397Sobrien  template<>
11050397Sobrien    template<typename V2>
11190075Sobrien      inline __gnu_test::pod_char::char_type
11290075Sobrien      __gnu_test::pod_char::char_type::from(const V2& v)
11390075Sobrien      {
11490075Sobrien	char_type ret = { static_cast<value_type>(v.value) };
11590075Sobrien	return ret;
11690075Sobrien      }
11790075Sobrien
11890075Sobrien  template<>
11990075Sobrien    template<typename V2>
12090075Sobrien      inline V2
12190075Sobrien      __gnu_test::pod_char::char_type::to(const char_type& c)
12290075Sobrien      {
12390075Sobrien	V2 ret = { c.value };
12490075Sobrien	return ret;
12590075Sobrien      }
12690075Sobrien
12790075Sobrien  template<>
12890075Sobrien    template<typename V2>
12990075Sobrien      inline __gnu_test::pod_uchar::char_type
13090075Sobrien      __gnu_test::pod_uchar::char_type::from(const V2& v)
13190075Sobrien      {
13290075Sobrien	char_type ret;
13390075Sobrien	ret.value = (v >> 5);
13490075Sobrien	return ret;
13590075Sobrien      }
13690075Sobrien
13790075Sobrien  template<>
13890075Sobrien    template<typename V2>
13990075Sobrien      inline V2
14090075Sobrien      __gnu_test::pod_uchar::char_type::to(const char_type& c)
14190075Sobrien      { return static_cast<V2>(c.value << 5); }
14290075Sobrien} // namespace __gnu_test
14390075Sobrien
14490075Sobriennamespace std
14590075Sobrien{
14690075Sobrien  // codecvt specialization
147  //
148  // The conversion performed by the specialization is not supposed to
149  // be useful, rather it has been designed to demonstrate the
150  // essential features of stateful conversions:
151  // * Number and value of bytes for each internal character depends on the
152  //   state in addition to the character itself.
153  // * Unshift produces an unshift sequence and resets the state. On input
154  //   the unshift sequence causes the state to be reset.
155  //
156  // The conversion for output is as follows:
157  // 1. Calculate the value tmp by xor-ing the state and the internal
158  //    character
159  // 2. Split tmp into either two or three bytes depending on the value of
160  //    state. Output those bytes.
161  // 3. tmp becomes the new value of state.
162  template<>
163    class codecvt<__gnu_test::pod_uchar, char, __gnu_test::pod_state>
164    : public __codecvt_abstract_base<__gnu_test::pod_uchar, char,
165				     __gnu_test::pod_state>
166    {
167    public:
168      typedef codecvt_base::result	result;
169      typedef __gnu_test::pod_uchar 	intern_type;
170      typedef char 			extern_type;
171      typedef __gnu_test::pod_state 	state_type;
172      typedef __codecvt_abstract_base<intern_type, extern_type, state_type>
173      base_type;
174
175      explicit codecvt(size_t refs = 0) : base_type(refs)
176      { }
177
178      static locale::id id;
179
180    protected:
181      ~codecvt()
182      { }
183
184      virtual result
185      do_out(state_type& state, const intern_type* from,
186	     const intern_type* from_end, const intern_type*& from_next,
187	     extern_type* to, extern_type* to_limit,
188	     extern_type*& to_next) const
189      {
190	while (from < from_end && to < to_limit)
191	  {
192	    unsigned char tmp = (state.value ^ from->value);
193	    if (state.value & 0x8)
194	      {
195		if (to >= to_limit - 2)
196		  break;
197		*to++ = (tmp & 0x7);
198		*to++ = ((tmp >> 3) & 0x7);
199		*to++ = ((tmp >> 6) & 0x3);
200	      }
201	    else
202	      {
203		if (to >= to_limit - 1)
204		  break;
205		*to++ = (tmp & 0xf);
206		*to++ = ((tmp >> 4) & 0xf);
207	      }
208	    state.value = tmp;
209	    ++from;
210	  }
211
212	from_next = from;
213	to_next = to;
214	return (from < from_end) ? partial : ok;
215      }
216
217      virtual result
218      do_in(state_type& state, const extern_type* from,
219	    const extern_type* from_end, const extern_type*& from_next,
220	    intern_type* to, intern_type* to_limit,
221	    intern_type*& to_next) const
222      {
223	while (from < from_end && to < to_limit)
224	  {
225	    unsigned char c = *from;
226	    if (c & 0xc0)
227	      {
228		// Unshift sequence
229		state.value &= c;
230		++from;
231		continue;
232	      }
233
234	    unsigned char tmp;
235	    if (state.value & 0x8)
236	      {
237		if (from >= from_end - 2)
238		  break;
239		tmp = (*from++ & 0x7);
240		tmp |= ((*from++ << 3) & 0x38);
241		tmp |= ((*from++ << 6) & 0xc0);
242	      }
243	    else
244	      {
245		if (from >= from_end - 1)
246		  break;
247		tmp = (*from++ & 0xf);
248		tmp |= ((*from++ << 4) & 0xf0);
249	      }
250	    to->value = (tmp ^ state.value);
251	    state.value = tmp;
252	    ++to;
253	  }
254
255	from_next = from;
256	to_next = to;
257	return (from < from_end) ? partial : ok;
258      }
259
260      virtual result
261      do_unshift(state_type& state, extern_type* to, extern_type* to_limit,
262		 extern_type*& to_next) const
263      {
264	for (unsigned int i = 0; i < CHAR_BIT; ++i)
265	  {
266	    unsigned int mask = (1 << i);
267	    if (state.value & mask)
268	      {
269		if (to == to_limit)
270		  {
271		    to_next = to;
272		    return partial;
273		  }
274
275		state.value &= ~mask;
276		*to++ = static_cast<unsigned char>(~mask);
277	      }
278	  }
279
280	to_next = to;
281	return state.value == 0 ? ok : error;
282      }
283
284      virtual int
285      do_encoding() const throw()
286      { return -1; }
287
288      virtual bool
289      do_always_noconv() const throw()
290      { return false; }
291
292      virtual int
293      do_length(state_type& state, const extern_type* from,
294		const extern_type* end, size_t max) const
295      {
296	const extern_type* beg = from;
297	while (from < end && max)
298	  {
299	    unsigned char c = *from;
300	    if (c & 0xc0)
301	      {
302		// Unshift sequence
303		state.value &= c;
304		++from;
305		continue;
306	      }
307
308	    unsigned char tmp;
309	    if (state.value & 0x8)
310	      {
311		if (from >= end - 2)
312		  break;
313		tmp = (*from++ & 0x7);
314		tmp |= ((*from++ << 3) & 0x38);
315		tmp |= ((*from++ << 6) & 0xc0);
316	      }
317	    else
318	      {
319		if (from >= end - 1)
320		  break;
321		tmp = (*from++ & 0xf);
322		tmp |= ((*from++ << 4) & 0xf0);
323	      }
324	    state.value = tmp;
325	    --max;
326	  }
327	return from - beg;
328      }
329
330      // Maximum 8 bytes unshift sequence followed by max 3 bytes for
331      // one character.
332      virtual int
333      do_max_length() const throw()
334      { return 11; }
335    };
336
337  template<>
338    class ctype<__gnu_test::pod_uchar>
339    : public __ctype_abstract_base<__gnu_test::pod_uchar>
340    {
341    public:
342      typedef __gnu_test::pod_uchar char_type;
343
344      explicit ctype(size_t refs  = 0)
345      : __ctype_abstract_base<__gnu_test::pod_uchar>(refs) { }
346
347      static locale::id id;
348
349    protected:
350      ~ctype()
351      { }
352
353      virtual bool
354      do_is(mask, char_type) const
355      { return false; }
356
357      virtual const char_type*
358      do_is(const char_type* low, const char_type* high, mask* vec) const
359      {
360	fill_n(vec, high - low, mask());
361	return high;
362      }
363
364      virtual const char_type*
365      do_scan_is(mask, const char_type*, const char_type* high) const
366      { return high; }
367
368      virtual const char_type*
369      do_scan_not(mask, const char_type* low, const char_type*) const
370      { return low; }
371
372      virtual char_type
373      do_toupper(char_type c) const
374      { return c; }
375
376      virtual const char_type*
377      do_toupper(char_type*, const char_type*  high) const
378      { return high; }
379
380      virtual char_type
381      do_tolower(char_type c) const
382      { return c; }
383
384      virtual const char_type*
385      do_tolower(char_type*, const char_type*  high) const
386      { return high; }
387
388      virtual char_type
389      do_widen(char c) const
390      { return __gnu_test::pod_uchar::from<char>(c); }
391
392      virtual const char*
393      do_widen(const char* low, const char* high, char_type* dest) const
394      {
395	transform(low, high, dest, &__gnu_test::pod_uchar::from<char>);
396	return high;
397      }
398
399      virtual char
400      do_narrow(char_type, char dfault) const
401      { return dfault; }
402
403      virtual const char_type*
404      do_narrow(const char_type* low, const char_type* high,
405		char dfault, char*  dest) const
406      {
407	fill_n(dest, high - low, dfault);
408	return high;
409      }
410    };
411
412  // numpunct specializations
413  template<>
414    class numpunct<__gnu_test::pod_uint>
415    : public locale::facet
416    {
417    public:
418      typedef __gnu_test::pod_uint    char_type;
419      typedef basic_string<char_type> string_type;
420
421      static locale::id id;
422
423      explicit
424      numpunct(size_t refs = 0)
425      : locale::facet(refs)
426      { }
427
428      char_type
429      decimal_point() const
430      { return this->do_decimal_point(); }
431
432      char_type
433      thousands_sep() const
434      { return this->do_thousands_sep(); }
435
436      string
437      grouping() const
438      { return this->do_grouping(); }
439
440      string_type
441      truename() const
442      { return this->do_truename(); }
443
444      string_type
445      falsename() const
446      { return this->do_falsename(); }
447
448    protected:
449      ~numpunct()
450      { }
451
452      virtual char_type
453      do_decimal_point() const
454      { return char_type(); }
455
456      virtual char_type
457      do_thousands_sep() const
458      { return char_type(); }
459
460      virtual string
461      do_grouping() const
462      { return string(); }
463
464      virtual string_type
465      do_truename() const
466      { return string_type(); }
467
468      virtual string_type
469      do_falsename() const
470      { return string_type(); }
471    };
472
473  template<>
474    class moneypunct<__gnu_test::pod_uint>
475    : public locale::facet, public money_base
476    {
477    public:
478      typedef __gnu_test::pod_uint    char_type;
479      typedef basic_string<char_type> string_type;
480
481      static locale::id id;
482      static const bool intl = false;
483
484      explicit
485      moneypunct(size_t refs = 0)
486      : locale::facet(refs)
487      { }
488
489      char_type
490      decimal_point() const
491      { return this->do_decimal_point(); }
492
493      char_type
494      thousands_sep() const
495      { return this->do_thousands_sep(); }
496
497      string
498      grouping() const
499      { return this->do_grouping(); }
500
501      string_type
502      curr_symbol() const
503      { return this->do_curr_symbol(); }
504
505      string_type
506      positive_sign() const
507      { return this->do_positive_sign(); }
508
509      string_type
510      negative_sign() const
511      { return this->do_negative_sign(); }
512
513      int
514      frac_digits() const
515      { return this->do_frac_digits(); }
516
517      pattern
518      pos_format() const
519      { return this->do_pos_format(); }
520
521      pattern
522      neg_format() const
523      { return this->do_neg_format(); }
524
525    protected:
526      ~moneypunct()
527      { }
528
529      virtual char_type
530      do_decimal_point() const
531      { return char_type(); }
532
533      virtual char_type
534      do_thousands_sep() const
535      { return char_type(); }
536
537      virtual string
538      do_grouping() const
539      { return string(); }
540
541      virtual string_type
542      do_curr_symbol() const
543      { return string_type(); }
544
545      string_type
546      do_positive_sign() const
547      { return string_type(); }
548
549      string_type
550      do_negative_sign() const
551      { return string_type(); }
552
553      int
554      do_frac_digits() const
555      { return 0; }
556
557      pattern
558      do_pos_format() const
559      { return pattern(); }
560
561      pattern
562      do_neg_format() const
563      { return pattern(); }
564     };
565} // namespace std
566
567#endif // _GLIBCXX_TESTSUITE_CHARACTER_H
568
569