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