Home | History | Annotate | Line # | Download | only in cxx
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