OSDN Git Service

2004-03-06 Paolo Carlini <pcarlini@suse.de>
[pf3gnuchains/gcc-fork.git] / libstdc++-v3 / testsuite / testsuite_character.h
1 // -*- C++ -*-
2 // Testing character type and state type with char_traits and codecvt
3 // specializations for the C++ library testsuite.
4 //
5 // Copyright (C) 2003 Free Software Foundation, Inc.
6 //
7 // This file is part of the GNU ISO C++ Library.  This library is free
8 // software; you can redistribute it and/or modify it under the
9 // terms of the GNU General Public License as published by the
10 // Free Software Foundation; either version 2, or (at your option)
11 // any later version.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License along
19 // with this library; see the file COPYING.  If not, write to the Free
20 // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
21 // USA.
22 //
23 // As a special exception, you may use this file as part of a free software
24 // library without restriction.  Specifically, if other files instantiate
25 // templates or use macros or inline functions from this file, or you compile
26 // this file and link it with other files to produce an executable, this
27 // file does not by itself cause the resulting executable to be covered by
28 // the GNU General Public License.  This exception does not however
29 // invalidate any other reasons why the executable file might be covered by
30 // the GNU General Public License.
31
32 #ifndef _GLIBCXX_TESTSUITE_CHARACTER_H
33 #define _GLIBCXX_TESTSUITE_CHARACTER_H
34
35 #include <string> // for char_traits
36 #include <locale> // for codecvt
37 #include <climits>
38
39 namespace __gnu_test
40 {  
41   // Character type
42   struct character
43   {
44     unsigned char val;
45
46     static character from_char(char c)
47     {
48       character ret;
49       ret.val = c;
50       return ret;
51     }
52   };
53
54   inline bool
55   operator==(const character& lhs, const character& rhs)
56   { return lhs.val == rhs.val; }
57
58   // State type.
59   struct conversion_state
60   {
61     unsigned int state;
62   };
63 }; // namespace __gnu_test
64
65 namespace std
66 {
67   // char_traits specialization. Meets the additional requirements for
68   // basic_filebuf.
69   template<>
70     struct char_traits<__gnu_test::character>
71     {
72       typedef __gnu_test::character char_type;
73       typedef unsigned int int_type;
74       typedef __gnu_test::conversion_state state_type;
75       typedef streamoff off_type;
76       typedef fpos<state_type> pos_type;
77
78       static void
79       assign(char_type& c1, const char_type& c2)
80       { c1 = c2; }
81
82       static bool
83       eq(const char_type& c1, const char_type& c2)
84       { return c1.val == c2.val; }
85
86       static bool
87       lt(const char_type& c1, const char_type& c2)
88       { return c1.val < c2.val; }
89
90       static int
91       compare(const char_type* s1, const char_type* s2, size_t n)
92       {
93         for (size_t i = 0; i < n; ++i)
94           {
95             if (lt(s1[i], s2[i]))
96               return -1;
97             else if (lt(s2[i], s1[i]))
98               return 1;
99           }
100         return 0;
101       }
102
103       static size_t
104       length(const char_type* s)
105       {
106         size_t n = 0;
107         while (!eq(s[n], char_type()))
108           ++n;
109         return n;
110       }
111
112       static const char_type*
113       find(const char_type* s, size_t n, const char_type& a)
114       {
115         for (size_t i = 0; i < n; ++i)
116           {
117             if (eq(s[i], a))
118               return s + i;
119           }
120         return NULL;
121       }
122
123       static char_type*
124       move(char_type* s1, const char_type* s2, size_t n)
125       {
126         if (s1 > s2)
127           {
128             for (size_t i = 0; i < n; ++i)
129               assign(s1[n - i - 1], s2[n - i - 1]);
130           }
131         else
132           {
133             for (size_t i = 0; i < n; ++i)
134               assign(s1[i], s2[i]);
135           }
136         return s1;
137       }
138
139       static char_type*
140       copy(char_type* s1, const char_type* s2, size_t n)
141       {
142         for (size_t i = 0; i < n; ++i)
143           assign(s1[i], s2[i]);
144         return s1;
145       }
146
147       static char_type*
148       assign(char_type* s, size_t n, char_type a)
149       {
150         for (size_t i = 0; i < n; ++i)
151           assign(s[i], a);
152         return s;
153       }
154
155       static int_type
156       not_eof(const int_type& c)
157       {
158         if (eq_int_type(c, eof()))
159           return 0;
160         return c;
161       }
162
163       // Note non-trivial conversion to maximize chance of catching bugs
164       static char_type
165       to_char_type(const int_type& c)
166       {
167         char_type ret;
168         ret.val = (c >> 5);
169         return ret;
170       }
171
172       static int_type
173       to_int_type(const char_type& c)
174       {
175         return c.val << 5;
176       }
177
178       static bool
179       eq_int_type(const int_type& c1, const int_type& c2)
180       { return c1 == c2; }
181
182       static int_type eof()
183       { return 0xf; }
184     };
185
186   // codecvt specialization
187   //
188   // The conversion performed by the specialization is not supposed to
189   // be useful, rather it has been designed to demonstrate the
190   // essential features of stateful conversions:
191   // * Number and value of bytes for each internal character depends on the
192   //   state in addition to the character itself.
193   // * Unshift produces an unshift sequence and resets the state. On input
194   //   the unshift sequence causes the state to be reset.
195   //
196   // The conversion for output is as follows:
197   // 1. Calculate the value tmp by xor-ing the state and the internal
198   //    character
199   // 2. Split tmp into either two or three bytes depending on the value of
200   //    state. Output those bytes.
201   // 3. tmp becomes the new value of state.
202   template<>
203     class codecvt<__gnu_test::character, char, __gnu_test::conversion_state>
204       : public locale::facet, public codecvt_base
205     {
206     public:
207       typedef __gnu_test::character intern_type;
208       typedef char extern_type;
209       typedef __gnu_test::conversion_state state_type;
210
211       explicit codecvt(size_t refs = 0)
212       : locale::facet(refs)
213       { }
214
215       result
216       out(state_type& state, const intern_type* from,
217           const intern_type* from_end, const intern_type*& from_next,
218           extern_type* to, extern_type* to_limit, extern_type*& to_next) const
219       {
220         return do_out(state, from, from_end, from_next,
221                       to, to_limit, to_next);
222       }
223
224       result
225       unshift(state_type& state, extern_type* to, extern_type* to_limit,
226               extern_type*& to_next) const
227       { return do_unshift(state, to, to_limit, to_next); }
228
229       result
230       in(state_type& state, const extern_type* from,
231          const extern_type* from_end, const extern_type*& from_next,
232          intern_type* to, intern_type* to_limit, intern_type*& to_next) const
233       {
234         return do_in(state, from, from_end, from_next,
235                      to, to_limit, to_next);
236       }
237
238       int
239       encoding() const throw()
240       { return do_encoding(); }
241
242       bool
243       always_noconv() const throw()
244       { return do_always_noconv(); }
245       
246       int
247       length(state_type& state, const extern_type* from,
248              const extern_type* end, size_t max) const
249       { return do_length(state, from, end, max); }
250       
251       int
252       max_length() const throw()
253       { return do_max_length(); }
254
255       static locale::id id;
256
257     protected:
258       ~codecvt()
259       { }
260
261       virtual result
262       do_out(state_type& state, const intern_type* from,
263              const intern_type* from_end, const intern_type*& from_next,
264              extern_type* to, extern_type* to_limit,
265              extern_type*& to_next) const
266       {
267         while (from < from_end && to < to_limit)
268           {
269             unsigned char tmp = (state.state ^ from->val);
270             if (state.state & 0x8)
271               {
272                 if (to >= to_limit - 2)
273                   break;
274                 *to++ = (tmp & 0x7);
275                 *to++ = ((tmp >> 3) & 0x7);
276                 *to++ = ((tmp >> 6) & 0x3);
277               }
278             else
279               {
280                 if (to >= to_limit - 1)
281                   break;
282                 *to++ = (tmp & 0xf);
283                 *to++ = ((tmp >> 4) & 0xf);
284               }
285             state.state = tmp;
286             ++from;
287           }
288
289         from_next = from;
290         to_next = to;
291         return (from < from_end) ? partial : ok;
292       }
293
294       virtual result
295       do_in(state_type& state, const extern_type* from,
296             const extern_type* from_end, const extern_type*& from_next,
297             intern_type* to, intern_type* to_limit,
298             intern_type*& to_next) const
299       {
300         while (from < from_end && to < to_limit)
301           {
302             unsigned char c = *from;
303             if (c & 0xc0)
304               {
305                 // Unshift sequence
306                 state.state &= c;
307                 ++from;
308                 continue;
309               }
310
311             unsigned char tmp;
312             if (state.state & 0x8)
313               {
314                 if (from >= from_end - 2)
315                   break;
316                 tmp = (*from++ & 0x7);
317                 tmp |= ((*from++ << 3) & 0x38);
318                 tmp |= ((*from++ << 6) & 0xc0);
319               }
320             else
321               {
322                 if (from >= from_end - 1)
323                   break;
324                 tmp = (*from++ & 0xf);
325                 tmp |= ((*from++ << 4) & 0xf0);
326               }
327             to->val = (tmp ^ state.state);
328             state.state = tmp;
329             ++to;
330           }
331
332         from_next = from;
333         to_next = to;
334         return (from < from_end) ? partial : ok;
335       }
336
337       virtual result
338       do_unshift(state_type& state, extern_type* to, extern_type* to_limit,
339                  extern_type*& to_next) const
340       {
341         for (unsigned int i = 0; i < CHAR_BIT; ++i)
342           {
343             unsigned int mask = (1 << i);
344             if (state.state & mask)
345               {
346                 if (to == to_limit)
347                   {
348                     to_next = to;
349                     return partial;
350                   }
351
352                 state.state &= ~mask;
353                 *to++ = static_cast<unsigned char>(~mask);
354               }
355           }
356
357         to_next = to;
358         return state.state == 0 ? ok : error;
359       }
360
361       virtual int
362       do_encoding() const throw()
363       { return -1; }
364
365       virtual bool
366       do_always_noconv() const throw()
367       { return false; }
368
369       virtual int
370       do_length(state_type& state, const extern_type* from,
371                 const extern_type* end, size_t max) const
372       {
373         const extern_type* beg = from;
374         while (from < end && max)
375           {
376             unsigned char c = *from;
377             if (c & 0xc0)
378               {
379                 // Unshift sequence
380                 state.state &= c;
381                 ++from;
382                 continue;
383               }
384
385             unsigned char tmp;
386             if (state.state & 0x8)
387               {
388                 if (from >= end - 2)
389                   break;
390                 tmp = (*from++ & 0x7);
391                 tmp |= ((*from++ << 3) & 0x38);
392                 tmp |= ((*from++ << 6) & 0xc0);
393               }
394             else
395               {
396                 if (from >= end - 1)
397                   break;
398                 tmp = (*from++ & 0xf);
399                 tmp |= ((*from++ << 4) & 0xf0);
400               }
401             state.state = tmp;
402             --max;
403           }
404         return from - beg;
405       }
406
407       // Maximum 8 bytes unshift sequence followed by max 3 bytes for
408       // one character.
409       virtual int
410       do_max_length() const throw()
411       { return 11; }
412     };
413
414   locale::id
415   codecvt<__gnu_test::character, char, __gnu_test::conversion_state>::id;
416 } // namespace std
417
418 #endif // _GLIBCXX_TESTSUITE_CHARACTER_H
419