]> git.ipfire.org Git - thirdparty/gcc.git/blob - libstdc++-v3/testsuite/testsuite_character.h
re PR libstdc++/12790 (basic_filebuf doesn't handle stateful encodings)
[thirdparty/gcc.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 // State type.
55 struct conversion_state
56 {
57 unsigned int state;
58 };
59 }; // namespace __gnu_test
60
61 namespace std
62 {
63 // char_traits specialization. Meets the additional requirements for
64 // basic_filebuf.
65 template<>
66 struct char_traits<__gnu_test::character>
67 {
68 typedef __gnu_test::character char_type;
69 typedef unsigned int int_type;
70 typedef __gnu_test::conversion_state state_type;
71 typedef streamoff off_type;
72 typedef fpos<state_type> pos_type;
73
74 static void
75 assign(char_type& c1, const char_type& c2)
76 { c1 = c2; }
77
78 static bool
79 eq(const char_type& c1, const char_type& c2)
80 { return c1.val == c2.val; }
81
82 static bool
83 lt(const char_type& c1, const char_type& c2)
84 { return c1.val < c2.val; }
85
86 static int
87 compare(const char_type* s1, const char_type* s2, size_t n)
88 {
89 for (size_t i = 0; i < n; ++i)
90 {
91 if (lt(s1[i], s2[i]))
92 return -1;
93 else if (lt(s2[i], s1[i]))
94 return 1;
95 }
96 return 0;
97 }
98
99 static size_t
100 length(const char_type* s)
101 {
102 size_t n = 0;
103 while (!eq(s[n], char_type()))
104 ++n;
105 return n;
106 }
107
108 static const char_type*
109 find(const char_type* s, size_t n, const char_type& a)
110 {
111 for (size_t i = 0; i < n; ++i)
112 {
113 if (eq(s[i], a))
114 return s + i;
115 }
116 return NULL;
117 }
118
119 static char_type*
120 move(char_type* s1, const char_type* s2, size_t n)
121 {
122 if (s1 > s2)
123 {
124 for (size_t i = 0; i < n; ++i)
125 assign(s1[n - i - 1], s2[n - i - 1]);
126 }
127 else
128 {
129 for (size_t i = 0; i < n; ++i)
130 assign(s1[i], s2[i]);
131 }
132 return s1;
133 }
134
135 static char_type*
136 copy(char_type* s1, const char_type* s2, size_t n)
137 {
138 for (size_t i = 0; i < n; ++i)
139 assign(s1[i], s2[i]);
140 return s1;
141 }
142
143 static char_type*
144 assign(char_type* s, size_t n, char_type a)
145 {
146 for (size_t i = 0; i < n; ++i)
147 assign(s[i], a);
148 return s;
149 }
150
151 static int_type
152 not_eof(const int_type& c)
153 {
154 if (eq_int_type(c, eof()))
155 return 0;
156 return c;
157 }
158
159 // Note non-trivial conversion to maximize chance of catching bugs
160 static char_type
161 to_char_type(const int_type& c)
162 {
163 char_type ret;
164 ret.val = (c >> 5);
165 return ret;
166 }
167
168 static int_type
169 to_int_type(const char_type& c)
170 {
171 return c.val << 5;
172 }
173
174 static bool
175 eq_int_type(const int_type& c1, const int_type& c2)
176 { return c1 == c2; }
177
178 static int_type eof()
179 { return 0xf; }
180 };
181
182 // codecvt specialization
183 //
184 // The conversion performed by the specialization is not supposed to
185 // be useful, rather it has been designed to demonstrate the
186 // essential features of stateful conversions:
187 // * Number and value of bytes for each internal character depends on the
188 // state in addition to the character itself.
189 // * Unshift produces an unshift sequence and resets the state. On input
190 // the unshift sequence causes the state to be reset.
191 //
192 // The conversion for output is as follows:
193 // 1. Calculate the value tmp by xor-ing the state and the internal
194 // character
195 // 2. Split tmp into either two or three bytes depending on the value of
196 // state. Output those bytes.
197 // 3. tmp becomes the new value of state.
198 template<>
199 class codecvt<__gnu_test::character, char, __gnu_test::conversion_state>
200 : public locale::facet, public codecvt_base
201 {
202 public:
203 typedef __gnu_test::character intern_type;
204 typedef char extern_type;
205 typedef __gnu_test::conversion_state state_type;
206
207 explicit codecvt(size_t refs = 0)
208 : locale::facet(refs)
209 { }
210
211 result
212 out(state_type& state, const intern_type* from,
213 const intern_type* from_end, const intern_type*& from_next,
214 extern_type* to, extern_type* to_limit, extern_type*& to_next) const
215 {
216 return do_out(state, from, from_end, from_next,
217 to, to_limit, to_next);
218 }
219
220 result
221 unshift(state_type& state, extern_type* to, extern_type* to_limit,
222 extern_type*& to_next) const
223 { return do_unshift(state, to, to_limit, to_next); }
224
225 result
226 in(state_type& state, const extern_type* from,
227 const extern_type* from_end, const extern_type*& from_next,
228 intern_type* to, intern_type* to_limit, intern_type*& to_next) const
229 {
230 return do_in(state, from, from_end, from_next,
231 to, to_limit, to_next);
232 }
233
234 int
235 encoding() const throw()
236 { return do_encoding(); }
237
238 bool
239 always_noconv() const throw()
240 { return do_always_noconv(); }
241
242 int
243 length(state_type& state, const extern_type* from,
244 const extern_type* end, size_t max) const
245 { return do_length(state, from, end, max); }
246
247 int
248 max_length() const throw()
249 { return do_max_length(); }
250
251 static locale::id id;
252
253 protected:
254 ~codecvt()
255 { }
256
257 virtual result
258 do_out(state_type& state, const intern_type* from,
259 const intern_type* from_end, const intern_type*& from_next,
260 extern_type* to, extern_type* to_limit,
261 extern_type*& to_next) const
262 {
263 while (from < from_end && to < to_limit)
264 {
265 unsigned char tmp = (state.state ^ from->val);
266 if (state.state & 0x8)
267 {
268 if (to >= to_limit - 2)
269 break;
270 *to++ = (tmp & 0x7);
271 *to++ = ((tmp >> 3) & 0x7);
272 *to++ = ((tmp >> 6) & 0x3);
273 }
274 else
275 {
276 if (to >= to_limit - 1)
277 break;
278 *to++ = (tmp & 0xf);
279 *to++ = ((tmp >> 4) & 0xf);
280 }
281 state.state = tmp;
282 ++from;
283 }
284
285 from_next = from;
286 to_next = to;
287 return (from < from_end) ? partial : ok;
288 }
289
290 virtual result
291 do_in(state_type& state, const extern_type* from,
292 const extern_type* from_end, const extern_type*& from_next,
293 intern_type* to, intern_type* to_limit,
294 intern_type*& to_next) const
295 {
296 while (from < from_end && to < to_limit)
297 {
298 unsigned char c = *from;
299 if (c & 0xc0)
300 {
301 // Unshift sequence
302 state.state &= c;
303 ++from;
304 continue;
305 }
306
307 unsigned char tmp;
308 if (state.state & 0x8)
309 {
310 if (from >= from_end - 2)
311 break;
312 tmp = (*from++ & 0x7);
313 tmp |= ((*from++ << 3) & 0x38);
314 tmp |= ((*from++ << 6) & 0xc0);
315 }
316 else
317 {
318 if (from >= from_end - 1)
319 break;
320 tmp = (*from++ & 0xf);
321 tmp |= ((*from++ << 4) & 0xf0);
322 }
323 to->val = (tmp ^ state.state);
324 state.state = tmp;
325 ++to;
326 }
327
328 from_next = from;
329 to_next = to;
330 return (from < from_end) ? partial : ok;
331 }
332
333 virtual result
334 do_unshift(state_type& state, extern_type* to, extern_type* to_limit,
335 extern_type*& to_next) const
336 {
337 for (unsigned int i = 0; i < CHAR_BIT; ++i)
338 {
339 unsigned int mask = (1 << i);
340 if (state.state & mask)
341 {
342 if (to == to_limit)
343 {
344 to_next = to;
345 return partial;
346 }
347
348 state.state &= ~mask;
349 *to++ = static_cast<unsigned char>(~mask);
350 }
351 }
352
353 to_next = to;
354 return state.state == 0 ? ok : error;
355 }
356
357 virtual int
358 do_encoding() const throw()
359 { return -1; }
360
361 virtual bool
362 do_always_noconv() const throw()
363 { return false; }
364
365 virtual int
366 do_length(state_type& state, const extern_type* from,
367 const extern_type* end, size_t max) const
368 {
369 const extern_type* beg = from;
370 while (from < end && max)
371 {
372 unsigned char c = *from;
373 if (c & 0xc0)
374 {
375 // Unshift sequence
376 state.state &= c;
377 ++from;
378 continue;
379 }
380
381 unsigned char tmp;
382 if (state.state & 0x8)
383 {
384 if (from >= end - 2)
385 break;
386 tmp = (*from++ & 0x7);
387 tmp |= ((*from++ << 3) & 0x38);
388 tmp |= ((*from++ << 6) & 0xc0);
389 }
390 else
391 {
392 if (from >= end - 1)
393 break;
394 tmp = (*from++ & 0xf);
395 tmp |= ((*from++ << 4) & 0xf0);
396 }
397 state.state = tmp;
398 --max;
399 }
400 return from - beg;
401 }
402
403 // Maximum 8 bytes unshift sequence followed by max 3 bytes for
404 // one character.
405 virtual int
406 do_max_length() const throw()
407 { return 11; }
408 };
409
410 locale::id
411 codecvt<__gnu_test::character, char, __gnu_test::conversion_state>::id;
412 } // namespace std
413
414 #endif // _GLIBCXX_TESTSUITE_CHARACTER_H
415