mpir/tests/cxx/t-istream.cc
2008-04-17 21:03:07 +00:00

541 lines
16 KiB
C++

/* Test istream formatted input.
Copyright 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
This file is part of the GNU MP Library.
The GNU MP Library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or (at your
option) any later version.
The GNU MP Library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the GNU MP Library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA. */
#include <iostream>
#include <cstdlib>
#include <cstring>
#include "gmp.h"
#include "gmp-impl.h"
#include "tests.h"
using namespace std;
// Under option_check_standard, the various test cases for mpz operator>>
// are put through the standard operator>> for long, and likewise mpf
// operator>> is put through double.
//
// In g++ 3.3 this results in some printouts about the final position
// indicated for something like ".e123". Our mpf code stops at the "e"
// since there's no mantissa digits, but g++ reads the whole thing and only
// then decides it's bad.
int option_check_standard = 0;
// On some versions of g++ 2.96 it's been observed that putback() may leave
// tellg() unchanged. We believe this is incorrect and presumably the
// result of a bug, since for instance it's ok in g++ 2.95 and g++ 3.3. We
// detect the problem at runtime and disable affected checks.
int putback_tellg_works = 1;
void
check_putback_tellg (void)
{
istringstream input ("hello");
streampos old_pos, new_pos;
char c;
input.get(c);
old_pos = input.tellg();
input.putback(c);
new_pos = input.tellg();
if (old_pos == new_pos)
{
cout << "Warning, istringstream has a bug: putback() doesn't update tellg().\n";;
cout << "Tests on tellg() will be skipped.\n";
putback_tellg_works = 0;
}
}
#define WRONG(str) \
do { \
cout << str ", data[" << i << "]\n"; \
cout << " input: \"" << data[i].input << "\"\n"; \
cout << " flags: " << hex << input.flags() << dec << "\n"; \
} while (0)
void
check_mpz (void)
{
static const struct {
const char *input;
int want_pos;
const char *want;
ios::fmtflags flags;
} data[] = {
{ "0", -1, "0", (ios::fmtflags) 0 },
{ "123", -1, "123", (ios::fmtflags) 0 },
{ "0123", -1, "83", (ios::fmtflags) 0 },
{ "0x123", -1, "291", (ios::fmtflags) 0 },
{ "-123", -1, "-123", (ios::fmtflags) 0 },
{ "-0123", -1, "-83", (ios::fmtflags) 0 },
{ "-0x123", -1, "-291", (ios::fmtflags) 0 },
{ "+123", -1, "123", (ios::fmtflags) 0 },
{ "+0123", -1, "83", (ios::fmtflags) 0 },
{ "+0x123", -1, "291", (ios::fmtflags) 0 },
{ "0", -1, "0", ios::dec },
{ "1f", 1, "1", ios::dec },
{ "011f", 3, "11", ios::dec },
{ "123", -1, "123", ios::dec },
{ "-1f", 2, "-1", ios::dec },
{ "-011f", 4, "-11", ios::dec },
{ "-123", -1, "-123", ios::dec },
{ "+1f", 2, "1", ios::dec },
{ "+011f", 4, "11", ios::dec },
{ "+123", -1, "123", ios::dec },
{ "0", -1, "0", ios::oct },
{ "123", -1, "83", ios::oct },
{ "-123", -1, "-83", ios::oct },
{ "+123", -1, "83", ios::oct },
{ "0", -1, "0", ios::hex },
{ "123", -1, "291", ios::hex },
{ "ff", -1, "255", ios::hex },
{ "FF", -1, "255", ios::hex },
{ "-123", -1, "-291", ios::hex },
{ "-ff", -1, "-255", ios::hex },
{ "-FF", -1, "-255", ios::hex },
{ "+123", -1, "291", ios::hex },
{ "+ff", -1, "255", ios::hex },
{ "+FF", -1, "255", ios::hex },
{ "ab", -1, "171", ios::hex },
{ "cd", -1, "205", ios::hex },
{ "ef", -1, "239", ios::hex },
{ " 123", 0, NULL, (ios::fmtflags) 0 }, // not without skipws
{ " 123", -1, "123", ios::skipws },
};
mpz_t got, want;
int got_ok, want_ok;
long got_si, want_si;
streampos init_tellg, got_pos, want_pos;
mpz_init (got);
mpz_init (want);
for (size_t i = 0; i < numberof (data); i++)
{
want_pos = (data[i].want_pos == -1
? strlen (data[i].input) : data[i].want_pos);
want_ok = (data[i].want != NULL);
if (data[i].want != NULL)
mpz_set_str_or_abort (want, data[i].want, 0);
else
mpz_set_ui (want, 0L);
if (option_check_standard && mpz_fits_slong_p (want))
{
istringstream input (data[i].input);
input.flags (data[i].flags);
init_tellg = input.tellg();
want_si = mpz_get_si (want);
input >> got_si;
got_ok = (input ? 1 : 0);
input.clear();
got_pos = input.tellg() - init_tellg;
if (got_ok != want_ok)
{
WRONG ("stdc++ operator>> wrong status, check_mpz");
cout << " want_ok: " << want_ok << "\n";
cout << " got_ok: " << got_ok << "\n";
}
if (want_ok && got_si != want_si)
{
WRONG ("stdc++ operator>> wrong result, check_mpz");
cout << " got_si: " << got_si << "\n";
cout << " want_si: " << want_si << "\n";
}
if (putback_tellg_works && got_pos != want_pos)
{
WRONG ("stdc++ operator>> wrong position, check_mpz");
cout << " want_pos: " << want_pos << "\n";
cout << " got_pos: " << got_pos << "\n";
}
}
{
istringstream input (data[i].input);
input.flags (data[i].flags);
init_tellg = input.tellg();
mpz_set_ui (got, 0xDEAD);
input >> got;
got_ok = (input ? 1 : 0);
input.clear();
got_pos = input.tellg() - init_tellg;
if (got_ok != want_ok)
{
WRONG ("mpz operator>> wrong status");
cout << " want_ok: " << want_ok << "\n";
cout << " got_ok: " << got_ok << "\n";
abort ();
}
if (want_ok && mpz_cmp (got, want) != 0)
{
WRONG ("mpz operator>> wrong result");
mpz_trace (" got ", got);
mpz_trace (" want", want);
abort ();
}
if (putback_tellg_works && got_pos != want_pos)
{
WRONG ("mpz operator>> wrong position");
cout << " want_pos: " << want_pos << "\n";
cout << " got_pos: " << got_pos << "\n";
abort ();
}
}
}
mpz_clear (got);
mpz_clear (want);
}
void
check_mpq (void)
{
static const struct {
const char *input;
int want_pos;
const char *want;
ios::fmtflags flags;
} data[] = {
{ "0", -1, "0", (ios::fmtflags) 0 },
{ "00", -1, "0", (ios::fmtflags) 0 },
{ "0x0", -1, "0", (ios::fmtflags) 0 },
{ "123/456", -1, "123/456", ios::dec },
{ "0123/456", -1, "123/456", ios::dec },
{ "123/0456", -1, "123/456", ios::dec },
{ "0123/0456", -1, "123/456", ios::dec },
{ "123/456", -1, "83/302", ios::oct },
{ "0123/456", -1, "83/302", ios::oct },
{ "123/0456", -1, "83/302", ios::oct },
{ "0123/0456", -1, "83/302", ios::oct },
{ "ab", -1, "171", ios::hex },
{ "cd", -1, "205", ios::hex },
{ "ef", -1, "239", ios::hex },
{ "0/0", -1, "0/0", (ios::fmtflags) 0 },
{ "5/8", -1, "5/8", (ios::fmtflags) 0 },
{ "0x5/0x8", -1, "5/8", (ios::fmtflags) 0 },
{ "123/456", -1, "123/456", (ios::fmtflags) 0 },
{ "123/0456", -1, "123/302", (ios::fmtflags) 0 },
{ "123/0x456", -1, "123/1110", (ios::fmtflags) 0 },
{ "123/0X456", -1, "123/1110", (ios::fmtflags) 0 },
{ "0123/123", -1, "83/123", (ios::fmtflags) 0 },
{ "0123/0123", -1, "83/83", (ios::fmtflags) 0 },
{ "0123/0x123", -1, "83/291", (ios::fmtflags) 0 },
{ "0123/0X123", -1, "83/291", (ios::fmtflags) 0 },
{ "0x123/123", -1, "291/123", (ios::fmtflags) 0 },
{ "0X123/0123", -1, "291/83", (ios::fmtflags) 0 },
{ "0x123/0x123", -1, "291/291", (ios::fmtflags) 0 },
{ " 123", 0, NULL, (ios::fmtflags) 0 }, // not without skipws
{ " 123", -1, "123", ios::skipws },
};
mpq_t got, want;
int got_ok, want_ok;
long got_si, want_si;
streampos init_tellg, got_pos, want_pos;
mpq_init (got);
mpq_init (want);
for (size_t i = 0; i < numberof (data); i++)
{
want_pos = (data[i].want_pos == -1
? strlen (data[i].input) : data[i].want_pos);
want_ok = (data[i].want != NULL);
if (data[i].want != NULL)
mpq_set_str_or_abort (want, data[i].want, 0);
else
mpq_set_ui (want, 0L, 1L);
if (option_check_standard
&& mpz_fits_slong_p (mpq_numref(want))
&& mpz_cmp_ui (mpq_denref(want), 1L) == 0)
{
istringstream input (data[i].input);
input.flags (data[i].flags);
init_tellg = input.tellg();
want_si = mpz_get_si (mpq_numref(want));
input >> got_si;
got_ok = (input ? 1 : 0);
input.clear();
got_pos = input.tellg() - init_tellg;
if (got_ok != want_ok)
{
WRONG ("stdc++ operator>> wrong status, check_mpq");
cout << " want_ok: " << want_ok << "\n";
cout << " got_ok: " << got_ok << "\n";
}
if (want_ok && want_si != got_si)
{
WRONG ("stdc++ operator>> wrong result, check_mpq");
cout << " got_si: " << got_si << "\n";
cout << " want_si: " << want_si << "\n";
}
if (putback_tellg_works && got_pos != want_pos)
{
WRONG ("stdc++ operator>> wrong position, check_mpq");
cout << " want_pos: " << want_pos << "\n";
cout << " got_pos: " << got_pos << "\n";
}
}
{
istringstream input (data[i].input);
input.flags (data[i].flags);
init_tellg = input.tellg();
mpq_set_si (got, 0xDEAD, 0xBEEF);
input >> got;
got_ok = (input ? 1 : 0);
input.clear();
got_pos = input.tellg() - init_tellg;
if (got_ok != want_ok)
{
WRONG ("mpq operator>> wrong status");
cout << " want_ok: " << want_ok << "\n";
cout << " got_ok: " << got_ok << "\n";
abort ();
}
// don't use mpq_equal, since we allow non-normalized values to be
// read, which can trigger ASSERTs in mpq_equal
if (want_ok && (mpz_cmp (mpq_numref (got), mpq_numref(want)) != 0
|| mpz_cmp (mpq_denref (got), mpq_denref(want)) != 0))
{
WRONG ("mpq operator>> wrong result");
mpq_trace (" got ", got);
mpq_trace (" want", want);
abort ();
}
if (putback_tellg_works && got_pos != want_pos)
{
WRONG ("mpq operator>> wrong position");
cout << " want_pos: " << want_pos << "\n";
cout << " got_pos: " << got_pos << "\n";
abort ();
}
}
}
mpq_clear (got);
mpq_clear (want);
}
void
check_mpf (void)
{
static const struct {
const char *input;
int want_pos;
const char *want;
ios::fmtflags flags;
} data[] = {
{ "0", -1, "0", (ios::fmtflags) 0 },
{ "+0", -1, "0", (ios::fmtflags) 0 },
{ "-0", -1, "0", (ios::fmtflags) 0 },
{ "0.0", -1, "0", (ios::fmtflags) 0 },
{ "0.", -1, "0", (ios::fmtflags) 0 },
{ ".0", -1, "0", (ios::fmtflags) 0 },
{ "+.0", -1, "0", (ios::fmtflags) 0 },
{ "-.0", -1, "0", (ios::fmtflags) 0 },
{ "+0.00", -1, "0", (ios::fmtflags) 0 },
{ "-0.000", -1, "0", (ios::fmtflags) 0 },
{ "+0.00", -1, "0", (ios::fmtflags) 0 },
{ "-0.000", -1, "0", (ios::fmtflags) 0 },
{ "0.0e0", -1, "0", (ios::fmtflags) 0 },
{ "0.e0", -1, "0", (ios::fmtflags) 0 },
{ ".0e0", -1, "0", (ios::fmtflags) 0 },
{ "0.0e-0", -1, "0", (ios::fmtflags) 0 },
{ "0.e-0", -1, "0", (ios::fmtflags) 0 },
{ ".0e-0", -1, "0", (ios::fmtflags) 0 },
{ "0.0e+0", -1, "0", (ios::fmtflags) 0 },
{ "0.e+0", -1, "0", (ios::fmtflags) 0 },
{ ".0e+0", -1, "0", (ios::fmtflags) 0 },
{ "1", -1, "1", (ios::fmtflags) 0 },
{ "+1", -1, "1", (ios::fmtflags) 0 },
{ "-1", -1, "-1", (ios::fmtflags) 0 },
{ " 0", 0, NULL, (ios::fmtflags) 0 }, // not without skipws
{ " 0", -1, "0", ios::skipws },
{ " +0", -1, "0", ios::skipws },
{ " -0", -1, "0", ios::skipws },
{ "+-123", 1, NULL, (ios::fmtflags) 0 },
{ "-+123", 1, NULL, (ios::fmtflags) 0 },
{ "1e+-123", 3, NULL, (ios::fmtflags) 0 },
{ "1e-+123", 3, NULL, (ios::fmtflags) 0 },
{ "e123", 0, NULL, (ios::fmtflags) 0 }, // at least one mantissa digit
{ ".e123", 1, NULL, (ios::fmtflags) 0 },
{ "+.e123", 2, NULL, (ios::fmtflags) 0 },
{ "-.e123", 2, NULL, (ios::fmtflags) 0 },
{ "123e", 4, NULL, (ios::fmtflags) 0 }, // at least one exponent digit
{ "123e-", 5, NULL, (ios::fmtflags) 0 },
{ "123e+", 5, NULL, (ios::fmtflags) 0 },
};
mpf_t got, want;
int got_ok, want_ok;
double got_d, want_d;
streampos init_tellg, got_pos, want_pos;
mpf_init (got);
mpf_init (want);
for (size_t i = 0; i < numberof (data); i++)
{
want_pos = (data[i].want_pos == -1
? strlen (data[i].input) : data[i].want_pos);
want_ok = (data[i].want != NULL);
if (data[i].want != NULL)
mpf_set_str_or_abort (want, data[i].want, 0);
else
mpf_set_ui (want, 0L);
want_d = mpf_get_d (want);
if (option_check_standard && mpf_cmp_d (want, want_d) == 0)
{
istringstream input (data[i].input);
input.flags (data[i].flags);
init_tellg = input.tellg();
input >> got_d;
got_ok = (input ? 1 : 0);
input.clear();
got_pos = input.tellg() - init_tellg;
if (got_ok != want_ok)
{
WRONG ("stdc++ operator>> wrong status, check_mpf");
cout << " want_ok: " << want_ok << "\n";
cout << " got_ok: " << got_ok << "\n";
}
if (want_ok && want_d != got_d)
{
WRONG ("stdc++ operator>> wrong result, check_mpf");
cout << " got: " << got_d << "\n";
cout << " want: " << want_d << "\n";
}
if (putback_tellg_works && got_pos != want_pos)
{
WRONG ("stdc++ operator>> wrong position, check_mpf");
cout << " want_pos: " << want_pos << "\n";
cout << " got_pos: " << got_pos << "\n";
}
}
{
istringstream input (data[i].input);
input.flags (data[i].flags);
init_tellg = input.tellg();
mpf_set_ui (got, 0xDEAD);
input >> got;
got_ok = (input ? 1 : 0);
input.clear();
got_pos = input.tellg() - init_tellg;
if (got_ok != want_ok)
{
WRONG ("mpf operator>> wrong status");
cout << " want_ok: " << want_ok << "\n";
cout << " got_ok: " << got_ok << "\n";
abort ();
}
if (want_ok && mpf_cmp (got, want) != 0)
{
WRONG ("mpf operator>> wrong result");
mpf_trace (" got ", got);
mpf_trace (" want", want);
abort ();
}
if (putback_tellg_works && got_pos != want_pos)
{
WRONG ("mpf operator>> wrong position");
cout << " want_pos: " << want_pos << "\n";
cout << " got_pos: " << got_pos << "\n";
abort ();
}
}
}
mpf_clear (got);
mpf_clear (want);
}
int
main (int argc, char *argv[])
{
if (argc > 1 && strcmp (argv[1], "-s") == 0)
option_check_standard = 1;
tests_start ();
check_putback_tellg ();
check_mpz ();
check_mpq ();
check_mpf ();
tests_end ();
return 0;
}