Revert "Partial fix to exception crashes on Windows."

This reverts commit 4746054635.
a300384 is the correct fix for this problem.
This commit is contained in:
John Ralls 2017-10-26 13:08:36 -07:00
parent a300304354
commit 4be826055a

View File

@ -85,13 +85,9 @@ GncNumeric::GncNumeric(double d) : m_num(0), m_den(1)
static uint64_t max_leg_value{INT64_C(1000000000000000000)};
if (std::isnan(d) || fabs(d) > max_leg_value)
{
#ifdef __MINGW32__
throw std::invalid_argument("Bad double");
#else
std::ostringstream msg;
std::ostringstream msg;
msg << "Unable to construct a GncNumeric from " << d << ".\n";
throw std::invalid_argument(msg.str());
#endif
}
constexpr auto max_num = static_cast<double>(INT64_MAX);
auto logval = log10(fabs(d));
@ -121,83 +117,6 @@ GncNumeric::GncNumeric(double d) : m_num(0), m_den(1)
using boost::regex;
using boost::smatch;
using boost::regex_search;
static bool
string_regex (const std::string& str, const regex& expr,
std::string& first, std::string& second)
{
smatch m;
if (regex_search(str, m, expr))
{
first = m[1].str();
second = m[2].str();
return true;
}
return false;
}
static bool
string_regex (const std::string& str, const regex& expr, std::string& string)
{
smatch m;
if (regex_search(str, m, expr))
{
string = m[1].str();
return true;
}
return false;
}
static bool
numeric_regex (const std::string& str, const regex& expr,
int64_t& num, int64_t& denom, int base1, int base2)
{
std::string first, second;
if (string_regex(str, expr, first, second))
{
num = stoll(first, nullptr, base1);
denom = stoll(second, nullptr, base2);
return true;
}
return false;
}
numeric_regex (const std::string& str, const regex& expr, int64_t& num,
int base)
{
std::string result;
if (string_regex(str, expr, result))
{
num = stoll(result, nullptr, base);
return true;
}
return false;
}
static bool
numeric_regex (const std::string& str, const regex& expr,
GncInt128& num, int64_t& den)
{
std::string first, second;
if (string_regex(str, expr, first, second))
{
GncInt128 high(stoll(first));
GncInt128 low(stoll(second));
den = powten(second.length());
num = high * den + (high > 0 ? low : -low);
return true;
}
return false;
}
static void
check_for_zero_denom (int64_t denom)
{
if (denom == 0)
throw std::invalid_argument("GncNumeric denominator can't be 0.");
}
GncNumeric::GncNumeric(const std::string& str, bool autoround)
{
static const std::string numer_frag("(-?[0-9]+)");
@ -215,70 +134,91 @@ GncNumeric::GncNumeric(const std::string& str, bool autoround)
static const regex hex_over_num(hex_frag + slash + denom_frag);
static const regex num_over_hex(numer_frag + slash + hex_frag);
static const regex decimal(numer_frag + "[.,]" + denom_frag);
smatch m;
/* The order of testing the regexes is from the more restrictve to the less
* restrictive, as less-restrictive ones will match patterns that would also
* match the more-restrictive and so invoke the wrong construction.
*/
if (str.empty())
throw std::invalid_argument("Can't construct a GncNumeric from an empty string.");
if (numeric_regex(str, hex_rational, m_num, m_den, 16, 16) ||
numeric_regex(str, hex_over_num, m_num, m_den, 16, 10) ||
numeric_regex(str, num_over_hex, m_num, m_den, 10, 16) ||
numeric_regex(str, numeral_rational, m_num, m_den, 10, 10))
if (regex_search(str, m, hex_rational))
{
check_for_zero_denom(m_den);
return;
GncNumeric n(stoll(m[1].str(), nullptr, 16),
stoll(m[2].str(), nullptr, 16));
m_num = n.num();
m_den = n.denom();
return;
}
GncInt128 n;
int64_t d;
if (numeric_regex(str, decimal, n, d))
if (regex_search(str, m, hex_over_num))
{
GncNumeric n(stoll(m[1].str(), nullptr, 16),
stoll(m[2].str()));
m_num = n.num();
m_den = n.denom();
return;
}
if (regex_search(str, m, num_over_hex))
{
GncNumeric n(stoll(m[1].str()),
stoll(m[2].str(), nullptr, 16));
m_num = n.num();
m_den = n.denom();
return;
}
if (regex_search(str, m, numeral_rational))
{
GncNumeric n(stoll(m[1].str()), stoll(m[2].str()));
m_num = n.num();
m_den = n.denom();
return;
}
if (regex_search(str, m, decimal))
{
GncInt128 high(stoll(m[1].str()));
GncInt128 low(stoll(m[2].str()));
int64_t d = powten(m[2].str().length());
GncInt128 n = high * d + (high > 0 ? low : -low);
if (!autoround && n.isBig())
{
#ifdef __MINGW32__
throw std::overflow_error("String overflowed, rounding.");
#else
std::ostringstream errmsg;
errmsg << "Decimal string " << str
<< " can't be represented in a GncNumeric without rounding.";
std::ostringstream errmsg;
errmsg << "Decimal string " << m[1].str() << "." << m[2].str()
<< "can't be represented in a GncNumeric without rounding.";
throw std::overflow_error(errmsg.str());
#endif
}
while (n.isBig() && d > 0)
{
n >>= 1;
d >>= 1;
}
if (d == 0 || n.isBig()) //Shouldn't happen, of course
if (n.isBig()) //Shouldn't happen, of course
{
d = d ? d : 1;
#ifdef __MINGW32__
throw std::overflow_error("String overflowed, reducing.");
#else
std::ostringstream errmsg;
errmsg << "Decimal string " << str
errmsg << "Decimal string " << m[1].str() << "." << m[2].str()
<< " can't be represented in a GncNumeric, even after reducing denom to " << d;
throw std::overflow_error(errmsg.str());
#endif
}
m_num = static_cast<int64_t>(n);
m_den = d;
return;
}
if (numeric_regex(str, hex, m_num, 16) ||
numeric_regex(str, numeral, m_num, 10))
{
m_den = 1;
GncNumeric gncn(static_cast<int64_t>(n), d);
m_num = gncn.num();
m_den = gncn.denom();
return;
}
if (regex_search(str, m, hex))
{
GncNumeric n(stoll(m[1].str(), nullptr, 16),INT64_C(1));
m_num = n.num();
m_den = n.denom();
return;
}
if (regex_search(str, m, numeral))
{
GncNumeric n(stoll(m[1].str()), INT64_C(1));
m_num = n.num();
m_den = n.denom();
return;
}
#ifdef __MINGW32__
throw std::invalid_argument("No numeric.");
#else
std::ostringstream errmsg;
errmsg << "String " << str << " contains no recognizable numeric value.";
throw std::invalid_argument(errmsg.str());
#endif
}
GncNumeric::operator gnc_numeric() const noexcept
@ -403,15 +343,11 @@ GncNumeric::to_decimal(unsigned int max_places) const
auto excess = m_den / powten(max_places);
if (m_num % excess)
{
#ifdef __MINGW32__
throw std::range_error("Number couldn't be reprensented without rounding");
#else
std::ostringstream msg;
msg << "GncNumeric " << *this
<< " could not be represented in " << max_places
<< " decimal places without rounding.\n";
throw std::range_error(msg.str());
#endif
}
return GncNumeric(m_num / excess, powten(max_places));
}
@ -442,25 +378,17 @@ GncNumeric::to_decimal(unsigned int max_places) const
}
catch (const std::invalid_argument& err)
{
#ifdef __MINGW32__
throw std::range_error("Number couldn't be represented without rounding");
#else
std::ostringstream msg;
msg << "GncNumeric " << *this
<< " could not be represented as a decimal without rounding.\n";
throw std::range_error(msg.str());
#endif
}
catch (const std::overflow_error& err)
{
#ifdef __MINGW32__
throw std::range_error("Number overflows as a decimal.");
#else
std::ostringstream msg;
msg << "GncNumeric " << *this
<< " overflows when attempting to convert it to decimal.\n";
throw std::range_error(msg.str());
#endif
}
}