literals should be long doubles to make float comparison exact

This commit is contained in:
Thomas Fussell 2015-10-02 10:02:54 -04:00
parent 8dc7342137
commit ffedc2cb33
2 changed files with 73 additions and 160 deletions

View File

@ -17,91 +17,96 @@
namespace {
std::vector<std::string> split_string(const std::string &string, char delim = ' ')
// return s after checking encoding, size, and illegal characters
std::string check_string(std::string s)
{
std::stringstream ss(string);
std::string part;
std::vector<std::string> parts;
while(std::getline(ss, part, delim))
if (s.size() == 0)
{
parts.push_back(part);
return s;
}
return parts;
// check encoding?
if (s.size() > 32767)
{
s = s.substr(0, 32767); // max string length in Excel
}
for (unsigned char c : s)
{
if (c <= 8 || c == 11 || c == 12 || (c >= 14 && c <= 31))
{
throw "illegal characters";
}
}
return s;
}
xlnt::value::type data_type_for_value(const std::string &value)
std::pair<bool, long double> cast_numeric(const std::string &s)
{
if(value.empty())
const char *str = s.c_str();
char *str_end = nullptr;
auto result = std::strtold(str, &str_end);
if (str_end != str + s.size()) return{ false, 0 };
return{ true, result };
}
std::pair<bool, long double> cast_percentage(const std::string &s)
{
if (s.back() == '%')
{
return xlnt::value::type::null;
auto number = cast_numeric(s.substr(0, s.size() - 1));
if (number.first)
{
return{ true, number.second / 100 };
}
}
if(value[0] == '0')
return { false, 0 };
}
std::pair<bool, xlnt::time> cast_time(const std::string &s)
{
xlnt::time result;
try
{
if(value.length() > 1)
auto last_colon = s.find_last_of(':');
if (last_colon == std::string::npos) return { false, result };
double seconds = std::stod(s.substr(last_colon + 1));
result.second = static_cast<int>(seconds);
result.microsecond = static_cast<int>((seconds - static_cast<double>(result.second)) * 1e6);
auto first_colon = s.find_first_of(':');
if (first_colon == last_colon)
{
if(value[1] == '.' || (value.length() > 2 && (value[1] == 'e' || value[1] == 'E')))
auto decimal_pos = s.find('.');
if (decimal_pos != std::string::npos)
{
auto first_non_number = std::find_if(value.begin() + 2, value.end(),
[](char c) { return !std::isdigit(c, std::locale::classic()); });
if(first_non_number == value.end())
{
return xlnt::value::type::numeric;
}
}
auto split = split_string(value, ':');
if(split.size() == 2 || split.size() == 3)
{
for(auto part : split)
{
try
{
std::stoi(part);
}
catch(std::invalid_argument)
{
return xlnt::value::type::string;
}
}
return xlnt::value::type::numeric;
result.minute = std::stoi(s.substr(0, first_colon));
}
else
{
return xlnt::value::type::string;
result.hour = std::stoi(s.substr(0, first_colon));
result.minute = result.second;
result.second = 0;
}
}
return xlnt::value::type::numeric;
}
else if(value[0] == '#')
{
return xlnt::value::type::error;
}
else
{
char *p;
strtod(value.c_str(), &p);
if(*p != 0)
{
static const std::vector<std::string> possible_booleans = {"TRUE", "true", "FALSE", "false"};
if(std::find(possible_booleans.begin(), possible_booleans.end(), value) != possible_booleans.end())
{
return xlnt::value::type::boolean;
}
if(value.back() == '%')
{
strtod(value.substr(0, value.length() - 1).c_str(), &p);
if(*p == 0)
{
return xlnt::value::type::numeric;
}
}
return xlnt::value::type::string;
}
else
{
return xlnt::value::type::numeric;
result.hour = std::stoi(s.substr(0, first_colon));
result.minute = std::stoi(s.substr(first_colon + 1, last_colon - first_colon - 1));
}
}
catch (std::invalid_argument)
{
return{ false, result };
}
return { true, result };
}
} // namespace
@ -161,98 +166,6 @@ void cell::set_value(const value &v)
d_->value_ = v;
}
// return s after checking encoding, size, and illegal characters
std::string check_string(std::string s)
{
if (s.size() == 0)
{
return s;
}
// check encoding?
if (s.size() > 32767)
{
s = s.substr(0, 32767); // max string length in Excel
}
for (unsigned char c : s)
{
if (c <= 8 || c == 11 || c == 12 || (c >= 14 && c <= 31))
{
throw "illegal characters";
}
}
return s;
}
std::pair<bool, long double> cast_numeric(const std::string &s)
{
const char *str = s.c_str();
char *str_end = nullptr;
auto result = std::strtold(str, &str_end);
if (str_end != str + s.size()) return{ false, 0 };
return{ true, result };
}
std::pair<bool, long double> cast_percentage(const std::string &s)
{
if (s.back() == '%')
{
auto number = cast_numeric(s.substr(0, s.size() - 1));
if (number.first)
{
return{ true, number.second / 100 };
}
}
return { false, 0 };
}
std::pair<bool, time> cast_time(const std::string &s)
{
time result;
try
{
auto last_colon = s.find_last_of(':');
if (last_colon == std::string::npos) return { false, result };
double seconds = std::stod(s.substr(last_colon + 1));
result.second = static_cast<int>(seconds);
result.microsecond = static_cast<int>((seconds - static_cast<double>(result.second)) * 1e6);
auto first_colon = s.find_first_of(':');
if (first_colon == last_colon)
{
auto decimal_pos = s.find('.');
if (decimal_pos != std::string::npos)
{
result.minute = std::stoi(s.substr(0, first_colon));
}
else
{
result.hour = std::stoi(s.substr(0, first_colon));
result.minute = result.second;
result.second = 0;
}
}
else
{
result.hour = std::stoi(s.substr(0, first_colon));
result.minute = std::stoi(s.substr(first_colon + 1, last_colon - first_colon - 1));
}
}
catch (std::invalid_argument)
{
return{ false, result };
}
return { true, result };
}
void cell::set_value(const std::string &s)
{
d_->is_date_ = false;

View File

@ -16,7 +16,7 @@ public:
xlnt::cell cell(ws, "A1");
cell.set_value("4.2");
TS_ASSERT(cell.get_value() == 4.2);
TS_ASSERT(cell.get_value() == 4.2L);
cell.set_value("-42.000");
TS_ASSERT(cell.get_value() == -42);
@ -25,10 +25,10 @@ public:
TS_ASSERT(cell.get_value() == 0);
cell.set_value("0.9999");
TS_ASSERT(cell.get_value() == 0.9999);
TS_ASSERT(cell.get_value() == 0.9999L);
cell.set_value("99E-02");
TS_ASSERT(cell.get_value() == 0.99);
TS_ASSERT(cell.get_value() == 0.99L);
cell.set_value("4");
TS_ASSERT(cell.get_value() == 4);
@ -40,7 +40,7 @@ public:
TS_ASSERT(cell.get_value() == 200);
cell.set_value("3.1%");
TS_ASSERT(cell.get_value() == 0.031);
TS_ASSERT(cell.get_value() == 0.031L);
cell.set_value("03:40:16");
TS_ASSERT(cell.get_value() == xlnt::time(3, 40, 16));