#include <fstream>
#include <iostream>
#include <sstream>
#include <limits>
struct double_istream
{
std::istream ∈
double_istream (std::istream &i) : in(i) {}
double_istream & parse_on_fail (double &x, bool neg)
{
const char *exp[] = {"", "inf", "Inf", "NaN", "nan"};
const char *e = exp[0];
int l = 0;
char parsed[4];
char *c = parsed;
if (neg) *c++ = '-';
in.clear();
if (!(in >> *c).good()) return *this; //If the stream is broken even before trying to read from it, it's pointless to try.
switch (*c) //Switch on the first character to parse, if 'i' or 'I', set up for Infinity, else if 'n' or 'N', set up for NaN
{
case 'i': e = exp[l=1]; break;
case 'I': e = exp[l=2]; break;
case 'N': e = exp[l=3]; break;
case 'n': e = exp[l=4]; break;
}
while (*c == *e)
{
if ((e-exp[l]) == 2) break;
++e;
if (!(in >> *++c).good()) break;
}
if (in.good() && *c == *e)
{
switch (l)
{
case 1: case 2: x = std::numeric_limits<double>::infinity(); break;
case 3: case 4: x = std::numeric_limits<double>::quiet_NaN(); break;
}
if (neg) x = -x;
return *this;
}
else if (!in.good())
{
if (!in.fail()) return *this;
in.clear(); --c;
}
do { in.putback(*c); } while (c-- != parsed);
in.setstate(std::ios_base::failbit);
return *this;
}
double_istream & operator >> (double &x) {
bool neg = false;
char c;
if (!in.good()) return *this;
while (isspace(c = in.peek())) in.get();
if (c == '-') { neg = true; }
in >> x;
if (! in.fail()) return *this;
return parse_on_fail(x, neg);
}
};
struct double_imanip
{
mutable std::istream *in;
const double_imanip & operator >> (double &x) const
{
double_istream(*in) >> x;
return *this;
}
std::istream & operator >> (const double_imanip &) const
{
return *in;
}
};
const double_imanip & operator >> (std::istream &in, const double_imanip &dm)
{
dm.in = ∈
return dm;
}
int main()
{
std::stringstream iss("1.0 -NaN inf Inf nan -inf NaN 1.2 inf");
double u, v, w, x, y, z, a, b, fail_double;
std::string fail_string;
iss >> double_imanip()
>> u >> v >> w >> x >> y >> z >> a >> b
>> double_imanip()
>> fail_double;
std::cout << u << " " << v << " " << w << " "
<< x << " " << y << " " << z << " " << a << " " << b << std::endl;
if (iss.fail()) {
iss.clear();
iss >> fail_string;
std::cout << fail_string << std::endl;
} else {
std::cout << "TEST FAILED" << std::endl;
}
}