t-istream.cc revision 1.1 1 /* Test istream formatted input.
2
3 Copyright 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
4
5 This file is part of the GNU MP Library.
6
7 The GNU MP Library is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11
12 The GNU MP Library is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
19
20 #include <iostream>
21 #include <cstdlib>
22 #include <cstring>
23
24 #include "gmp.h"
25 #include "gmp-impl.h"
26 #include "tests.h"
27
28 using namespace std;
29
30
31 // Under option_check_standard, the various test cases for mpz operator>>
32 // are put through the standard operator>> for long, and likewise mpf
33 // operator>> is put through double.
34 //
35 // In g++ 3.3 this results in some printouts about the final position
36 // indicated for something like ".e123". Our mpf code stops at the "e"
37 // since there's no mantissa digits, but g++ reads the whole thing and only
38 // then decides it's bad.
39
40 int option_check_standard = 0;
41
42
43 // On some versions of g++ 2.96 it's been observed that putback() may leave
44 // tellg() unchanged. We believe this is incorrect and presumably the
45 // result of a bug, since for instance it's ok in g++ 2.95 and g++ 3.3. We
46 // detect the problem at runtime and disable affected checks.
47
48 int putback_tellg_works = 1;
49
50 void
51 check_putback_tellg (void)
52 {
53 istringstream input ("hello");
54 streampos old_pos, new_pos;
55 char c;
56
57 input.get(c);
58 old_pos = input.tellg();
59 input.putback(c);
60 new_pos = input.tellg();
61
62 if (old_pos == new_pos)
63 {
64 cout << "Warning, istringstream has a bug: putback() doesn't update tellg().\n";;
65 cout << "Tests on tellg() will be skipped.\n";
66 putback_tellg_works = 0;
67 }
68 }
69
70
71 #define WRONG(str) \
72 do { \
73 cout << str ", data[" << i << "]\n"; \
74 cout << " input: \"" << data[i].input << "\"\n"; \
75 cout << " flags: " << hex << input.flags() << dec << "\n"; \
76 } while (0)
77
78 void
79 check_mpz (void)
80 {
81 static const struct {
82 const char *input;
83 int want_pos;
84 const char *want;
85 ios::fmtflags flags;
86
87 } data[] = {
88
89 { "0", -1, "0", (ios::fmtflags) 0 },
90 { "123", -1, "123", (ios::fmtflags) 0 },
91 { "0123", -1, "83", (ios::fmtflags) 0 },
92 { "0x123", -1, "291", (ios::fmtflags) 0 },
93 { "-123", -1, "-123", (ios::fmtflags) 0 },
94 { "-0123", -1, "-83", (ios::fmtflags) 0 },
95 { "-0x123", -1, "-291", (ios::fmtflags) 0 },
96 { "+123", -1, "123", (ios::fmtflags) 0 },
97 { "+0123", -1, "83", (ios::fmtflags) 0 },
98 { "+0x123", -1, "291", (ios::fmtflags) 0 },
99
100 { "0", -1, "0", ios::dec },
101 { "1f", 1, "1", ios::dec },
102 { "011f", 3, "11", ios::dec },
103 { "123", -1, "123", ios::dec },
104 { "-1f", 2, "-1", ios::dec },
105 { "-011f", 4, "-11", ios::dec },
106 { "-123", -1, "-123", ios::dec },
107 { "+1f", 2, "1", ios::dec },
108 { "+011f", 4, "11", ios::dec },
109 { "+123", -1, "123", ios::dec },
110
111 { "0", -1, "0", ios::oct },
112 { "123", -1, "83", ios::oct },
113 { "-123", -1, "-83", ios::oct },
114 { "+123", -1, "83", ios::oct },
115
116 { "0", -1, "0", ios::hex },
117 { "123", -1, "291", ios::hex },
118 { "ff", -1, "255", ios::hex },
119 { "FF", -1, "255", ios::hex },
120 { "-123", -1, "-291", ios::hex },
121 { "-ff", -1, "-255", ios::hex },
122 { "-FF", -1, "-255", ios::hex },
123 { "+123", -1, "291", ios::hex },
124 { "+ff", -1, "255", ios::hex },
125 { "+FF", -1, "255", ios::hex },
126 { "ab", -1, "171", ios::hex },
127 { "cd", -1, "205", ios::hex },
128 { "ef", -1, "239", ios::hex },
129
130 { " 123", 0, NULL, (ios::fmtflags) 0 }, // not without skipws
131 { " 123", -1, "123", ios::skipws },
132 };
133
134 mpz_t got, want;
135 int got_ok, want_ok;
136 long got_si, want_si;
137 streampos init_tellg, got_pos, want_pos;
138
139 mpz_init (got);
140 mpz_init (want);
141
142 for (size_t i = 0; i < numberof (data); i++)
143 {
144 want_pos = (data[i].want_pos == -1
145 ? strlen (data[i].input) : data[i].want_pos);
146
147 want_ok = (data[i].want != NULL);
148
149 if (data[i].want != NULL)
150 mpz_set_str_or_abort (want, data[i].want, 0);
151 else
152 mpz_set_ui (want, 0L);
153
154 if (option_check_standard && mpz_fits_slong_p (want))
155 {
156 istringstream input (data[i].input);
157 input.flags (data[i].flags);
158 init_tellg = input.tellg();
159 want_si = mpz_get_si (want);
160
161 input >> got_si;
162 got_ok = (input ? 1 : 0);
163 input.clear();
164 got_pos = input.tellg() - init_tellg;
165
166 if (got_ok != want_ok)
167 {
168 WRONG ("stdc++ operator>> wrong status, check_mpz");
169 cout << " want_ok: " << want_ok << "\n";
170 cout << " got_ok: " << got_ok << "\n";
171 }
172 if (want_ok && got_si != want_si)
173 {
174 WRONG ("stdc++ operator>> wrong result, check_mpz");
175 cout << " got_si: " << got_si << "\n";
176 cout << " want_si: " << want_si << "\n";
177 }
178 if (putback_tellg_works && got_pos != want_pos)
179 {
180 WRONG ("stdc++ operator>> wrong position, check_mpz");
181 cout << " want_pos: " << want_pos << "\n";
182 cout << " got_pos: " << got_pos << "\n";
183 }
184 }
185
186 {
187 istringstream input (data[i].input);
188 input.flags (data[i].flags);
189 init_tellg = input.tellg();
190
191 mpz_set_ui (got, 0xDEAD);
192 input >> got;
193 got_ok = (input ? 1 : 0);
194 input.clear();
195 got_pos = input.tellg() - init_tellg;
196
197 if (got_ok != want_ok)
198 {
199 WRONG ("mpz operator>> wrong status");
200 cout << " want_ok: " << want_ok << "\n";
201 cout << " got_ok: " << got_ok << "\n";
202 abort ();
203 }
204 if (want_ok && mpz_cmp (got, want) != 0)
205 {
206 WRONG ("mpz operator>> wrong result");
207 mpz_trace (" got ", got);
208 mpz_trace (" want", want);
209 abort ();
210 }
211 if (putback_tellg_works && got_pos != want_pos)
212 {
213 WRONG ("mpz operator>> wrong position");
214 cout << " want_pos: " << want_pos << "\n";
215 cout << " got_pos: " << got_pos << "\n";
216 abort ();
217 }
218 }
219 }
220
221 mpz_clear (got);
222 mpz_clear (want);
223 }
224
225 void
226 check_mpq (void)
227 {
228 static const struct {
229 const char *input;
230 int want_pos;
231 const char *want;
232 ios::fmtflags flags;
233
234 } data[] = {
235
236 { "0", -1, "0", (ios::fmtflags) 0 },
237 { "00", -1, "0", (ios::fmtflags) 0 },
238 { "0x0", -1, "0", (ios::fmtflags) 0 },
239
240 { "123/456", -1, "123/456", ios::dec },
241 { "0123/456", -1, "123/456", ios::dec },
242 { "123/0456", -1, "123/456", ios::dec },
243 { "0123/0456", -1, "123/456", ios::dec },
244
245 { "123/456", -1, "83/302", ios::oct },
246 { "0123/456", -1, "83/302", ios::oct },
247 { "123/0456", -1, "83/302", ios::oct },
248 { "0123/0456", -1, "83/302", ios::oct },
249
250 { "ab", -1, "171", ios::hex },
251 { "cd", -1, "205", ios::hex },
252 { "ef", -1, "239", ios::hex },
253
254 { "0/0", -1, "0/0", (ios::fmtflags) 0 },
255 { "5/8", -1, "5/8", (ios::fmtflags) 0 },
256 { "0x5/0x8", -1, "5/8", (ios::fmtflags) 0 },
257
258 { "123/456", -1, "123/456", (ios::fmtflags) 0 },
259 { "123/0456", -1, "123/302", (ios::fmtflags) 0 },
260 { "123/0x456", -1, "123/1110", (ios::fmtflags) 0 },
261 { "123/0X456", -1, "123/1110", (ios::fmtflags) 0 },
262
263 { "0123/123", -1, "83/123", (ios::fmtflags) 0 },
264 { "0123/0123", -1, "83/83", (ios::fmtflags) 0 },
265 { "0123/0x123", -1, "83/291", (ios::fmtflags) 0 },
266 { "0123/0X123", -1, "83/291", (ios::fmtflags) 0 },
267
268 { "0x123/123", -1, "291/123", (ios::fmtflags) 0 },
269 { "0X123/0123", -1, "291/83", (ios::fmtflags) 0 },
270 { "0x123/0x123", -1, "291/291", (ios::fmtflags) 0 },
271
272 { " 123", 0, NULL, (ios::fmtflags) 0 }, // not without skipws
273 { " 123", -1, "123", ios::skipws },
274 };
275
276 mpq_t got, want;
277 int got_ok, want_ok;
278 long got_si, want_si;
279 streampos init_tellg, got_pos, want_pos;
280
281 mpq_init (got);
282 mpq_init (want);
283
284 for (size_t i = 0; i < numberof (data); i++)
285 {
286 want_pos = (data[i].want_pos == -1
287 ? strlen (data[i].input) : data[i].want_pos);
288
289 want_ok = (data[i].want != NULL);
290
291 if (data[i].want != NULL)
292 mpq_set_str_or_abort (want, data[i].want, 0);
293 else
294 mpq_set_ui (want, 0L, 1L);
295
296 if (option_check_standard
297 && mpz_fits_slong_p (mpq_numref(want))
298 && mpz_cmp_ui (mpq_denref(want), 1L) == 0)
299 {
300 istringstream input (data[i].input);
301 input.flags (data[i].flags);
302 init_tellg = input.tellg();
303 want_si = mpz_get_si (mpq_numref(want));
304
305 input >> got_si;
306 got_ok = (input ? 1 : 0);
307 input.clear();
308 got_pos = input.tellg() - init_tellg;
309
310 if (got_ok != want_ok)
311 {
312 WRONG ("stdc++ operator>> wrong status, check_mpq");
313 cout << " want_ok: " << want_ok << "\n";
314 cout << " got_ok: " << got_ok << "\n";
315 }
316 if (want_ok && want_si != got_si)
317 {
318 WRONG ("stdc++ operator>> wrong result, check_mpq");
319 cout << " got_si: " << got_si << "\n";
320 cout << " want_si: " << want_si << "\n";
321 }
322 if (putback_tellg_works && got_pos != want_pos)
323 {
324 WRONG ("stdc++ operator>> wrong position, check_mpq");
325 cout << " want_pos: " << want_pos << "\n";
326 cout << " got_pos: " << got_pos << "\n";
327 }
328 }
329
330 {
331 istringstream input (data[i].input);
332 input.flags (data[i].flags);
333 init_tellg = input.tellg();
334 mpq_set_si (got, 0xDEAD, 0xBEEF);
335
336 input >> got;
337 got_ok = (input ? 1 : 0);
338 input.clear();
339 got_pos = input.tellg() - init_tellg;
340
341 if (got_ok != want_ok)
342 {
343 WRONG ("mpq operator>> wrong status");
344 cout << " want_ok: " << want_ok << "\n";
345 cout << " got_ok: " << got_ok << "\n";
346 abort ();
347 }
348 // don't use mpq_equal, since we allow non-normalized values to be
349 // read, which can trigger ASSERTs in mpq_equal
350 if (want_ok && (mpz_cmp (mpq_numref (got), mpq_numref(want)) != 0
351 || mpz_cmp (mpq_denref (got), mpq_denref(want)) != 0))
352 {
353 WRONG ("mpq operator>> wrong result");
354 mpq_trace (" got ", got);
355 mpq_trace (" want", want);
356 abort ();
357 }
358 if (putback_tellg_works && got_pos != want_pos)
359 {
360 WRONG ("mpq operator>> wrong position");
361 cout << " want_pos: " << want_pos << "\n";
362 cout << " got_pos: " << got_pos << "\n";
363 abort ();
364 }
365 }
366 }
367
368 mpq_clear (got);
369 mpq_clear (want);
370 }
371
372
373 void
374 check_mpf (void)
375 {
376 static const struct {
377 const char *input;
378 int want_pos;
379 const char *want;
380 ios::fmtflags flags;
381
382 } data[] = {
383
384 { "0", -1, "0", (ios::fmtflags) 0 },
385 { "+0", -1, "0", (ios::fmtflags) 0 },
386 { "-0", -1, "0", (ios::fmtflags) 0 },
387 { "0.0", -1, "0", (ios::fmtflags) 0 },
388 { "0.", -1, "0", (ios::fmtflags) 0 },
389 { ".0", -1, "0", (ios::fmtflags) 0 },
390 { "+.0", -1, "0", (ios::fmtflags) 0 },
391 { "-.0", -1, "0", (ios::fmtflags) 0 },
392 { "+0.00", -1, "0", (ios::fmtflags) 0 },
393 { "-0.000", -1, "0", (ios::fmtflags) 0 },
394 { "+0.00", -1, "0", (ios::fmtflags) 0 },
395 { "-0.000", -1, "0", (ios::fmtflags) 0 },
396 { "0.0e0", -1, "0", (ios::fmtflags) 0 },
397 { "0.e0", -1, "0", (ios::fmtflags) 0 },
398 { ".0e0", -1, "0", (ios::fmtflags) 0 },
399 { "0.0e-0", -1, "0", (ios::fmtflags) 0 },
400 { "0.e-0", -1, "0", (ios::fmtflags) 0 },
401 { ".0e-0", -1, "0", (ios::fmtflags) 0 },
402 { "0.0e+0", -1, "0", (ios::fmtflags) 0 },
403 { "0.e+0", -1, "0", (ios::fmtflags) 0 },
404 { ".0e+0", -1, "0", (ios::fmtflags) 0 },
405
406 { "1", -1, "1", (ios::fmtflags) 0 },
407 { "+1", -1, "1", (ios::fmtflags) 0 },
408 { "-1", -1, "-1", (ios::fmtflags) 0 },
409
410 { " 0", 0, NULL, (ios::fmtflags) 0 }, // not without skipws
411 { " 0", -1, "0", ios::skipws },
412 { " +0", -1, "0", ios::skipws },
413 { " -0", -1, "0", ios::skipws },
414
415 { "+-123", 1, NULL, (ios::fmtflags) 0 },
416 { "-+123", 1, NULL, (ios::fmtflags) 0 },
417 { "1e+-123", 3, NULL, (ios::fmtflags) 0 },
418 { "1e-+123", 3, NULL, (ios::fmtflags) 0 },
419
420 { "e123", 0, NULL, (ios::fmtflags) 0 }, // at least one mantissa digit
421 { ".e123", 1, NULL, (ios::fmtflags) 0 },
422 { "+.e123", 2, NULL, (ios::fmtflags) 0 },
423 { "-.e123", 2, NULL, (ios::fmtflags) 0 },
424
425 { "123e", 4, NULL, (ios::fmtflags) 0 }, // at least one exponent digit
426 { "123e-", 5, NULL, (ios::fmtflags) 0 },
427 { "123e+", 5, NULL, (ios::fmtflags) 0 },
428 };
429
430 mpf_t got, want;
431 int got_ok, want_ok;
432 double got_d, want_d;
433 streampos init_tellg, got_pos, want_pos;
434
435 mpf_init (got);
436 mpf_init (want);
437
438 for (size_t i = 0; i < numberof (data); i++)
439 {
440 want_pos = (data[i].want_pos == -1
441 ? strlen (data[i].input) : data[i].want_pos);
442
443 want_ok = (data[i].want != NULL);
444
445 if (data[i].want != NULL)
446 mpf_set_str_or_abort (want, data[i].want, 0);
447 else
448 mpf_set_ui (want, 0L);
449
450 want_d = mpf_get_d (want);
451 if (option_check_standard && mpf_cmp_d (want, want_d) == 0)
452 {
453 istringstream input (data[i].input);
454 input.flags (data[i].flags);
455 init_tellg = input.tellg();
456
457 input >> got_d;
458 got_ok = (input ? 1 : 0);
459 input.clear();
460 got_pos = input.tellg() - init_tellg;
461
462 if (got_ok != want_ok)
463 {
464 WRONG ("stdc++ operator>> wrong status, check_mpf");
465 cout << " want_ok: " << want_ok << "\n";
466 cout << " got_ok: " << got_ok << "\n";
467 }
468 if (want_ok && want_d != got_d)
469 {
470 WRONG ("stdc++ operator>> wrong result, check_mpf");
471 cout << " got: " << got_d << "\n";
472 cout << " want: " << want_d << "\n";
473 }
474 if (putback_tellg_works && got_pos != want_pos)
475 {
476 WRONG ("stdc++ operator>> wrong position, check_mpf");
477 cout << " want_pos: " << want_pos << "\n";
478 cout << " got_pos: " << got_pos << "\n";
479 }
480 }
481
482 {
483 istringstream input (data[i].input);
484 input.flags (data[i].flags);
485 init_tellg = input.tellg();
486
487 mpf_set_ui (got, 0xDEAD);
488 input >> got;
489 got_ok = (input ? 1 : 0);
490 input.clear();
491 got_pos = input.tellg() - init_tellg;
492
493 if (got_ok != want_ok)
494 {
495 WRONG ("mpf operator>> wrong status");
496 cout << " want_ok: " << want_ok << "\n";
497 cout << " got_ok: " << got_ok << "\n";
498 abort ();
499 }
500 if (want_ok && mpf_cmp (got, want) != 0)
501 {
502 WRONG ("mpf operator>> wrong result");
503 mpf_trace (" got ", got);
504 mpf_trace (" want", want);
505 abort ();
506 }
507 if (putback_tellg_works && got_pos != want_pos)
508 {
509 WRONG ("mpf operator>> wrong position");
510 cout << " want_pos: " << want_pos << "\n";
511 cout << " got_pos: " << got_pos << "\n";
512 abort ();
513 }
514 }
515 }
516
517 mpf_clear (got);
518 mpf_clear (want);
519 }
520
521
522
523 int
524 main (int argc, char *argv[])
525 {
526 if (argc > 1 && strcmp (argv[1], "-s") == 0)
527 option_check_standard = 1;
528
529 tests_start ();
530
531 check_putback_tellg ();
532 check_mpz ();
533 check_mpq ();
534 check_mpf ();
535
536 tests_end ();
537 return 0;
538 }
539