mirror of
https://github.com/fastfloat/fast_float.git
synced 2026-10-28 18:07:16 +08:00
Leave std::float32_t/std::float64_t unmodified on invalid input (fixes #424)
The fixed-width wrappers parsed into a zero-initialized temporary and copied it back unconditionally, so invalid input overwrote the destination with zero. Copy back only when the result is not invalid_argument, as required by [charconv.from.chars]/1.
This commit is contained in:
parent
033f64f608
commit
9cd6dfc8e3
@ -158,7 +158,10 @@ template <> struct from_chars_caller<std::float32_t> {
|
|||||||
// float32_t
|
// float32_t
|
||||||
float val = 0.0f;
|
float val = 0.0f;
|
||||||
auto ret = from_chars_advanced(first, last, val, options);
|
auto ret = from_chars_advanced(first, last, val, options);
|
||||||
value = val;
|
// If no characters match the pattern, value must be left unmodified.
|
||||||
|
if (ret.ec != std::errc::invalid_argument) {
|
||||||
|
value = val;
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -175,7 +178,10 @@ template <> struct from_chars_caller<std::float64_t> {
|
|||||||
// float64_t
|
// float64_t
|
||||||
double val = 0.0;
|
double val = 0.0;
|
||||||
auto ret = from_chars_advanced(first, last, val, options);
|
auto ret = from_chars_advanced(first, last, val, options);
|
||||||
value = val;
|
// If no characters match the pattern, value must be left unmodified.
|
||||||
|
if (ret.ec != std::errc::invalid_argument) {
|
||||||
|
value = val;
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <limits>
|
||||||
|
#include <string_view>
|
||||||
#include "fast_float/fast_float.h"
|
#include "fast_float/fast_float.h"
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
@ -9,6 +11,39 @@
|
|||||||
#include <stdfloat>
|
#include <stdfloat>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// If no characters match the pattern, value must be left unmodified
|
||||||
|
// (see https://github.com/fastfloat/fast_float/issues/424).
|
||||||
|
template <typename T> bool check_invalid_input_preserves_value() {
|
||||||
|
std::vector<std::string_view> const invalid_inputs{"x", "", "-", ".", "e1",
|
||||||
|
"-x", "na", "+"};
|
||||||
|
for (auto const &f : invalid_inputs) {
|
||||||
|
T result = T(42);
|
||||||
|
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result);
|
||||||
|
if (answer.ec != std::errc::invalid_argument || answer.ptr != f.data()) {
|
||||||
|
std::cerr << "Expected invalid_argument for input: \"" << f << "\""
|
||||||
|
<< std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (result != T(42)) {
|
||||||
|
std::cerr << "Value modified on invalid input: \"" << f << "\" got "
|
||||||
|
<< result << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Out-of-range input must still store the documented value.
|
||||||
|
std::string_view const too_large = "1e999";
|
||||||
|
T result = T(42);
|
||||||
|
auto answer = fast_float::from_chars(
|
||||||
|
too_large.data(), too_large.data() + too_large.size(), result);
|
||||||
|
if (answer.ec != std::errc::result_out_of_range ||
|
||||||
|
result != std::numeric_limits<T>::infinity()) {
|
||||||
|
std::cerr << "Expected infinity and result_out_of_range for \"1e999\""
|
||||||
|
<< std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
// Write some testcases for the parsing of floating point numbers in the
|
// Write some testcases for the parsing of floating point numbers in the
|
||||||
// float32_t type. We use the from_chars function defined in this library.
|
// float32_t type. We use the from_chars function defined in this library.
|
||||||
@ -33,6 +68,9 @@ int main() {
|
|||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!check_invalid_input_preserves_value<std::float32_t>()) {
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
std::cout << "No std::float32_t type available." << std::endl;
|
std::cout << "No std::float32_t type available." << std::endl;
|
||||||
#endif
|
#endif
|
||||||
@ -60,6 +98,9 @@ int main() {
|
|||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!check_invalid_input_preserves_value<std::float64_t>()) {
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
std::cout << "No std::float64_t type available." << std::endl;
|
std::cout << "No std::float64_t type available." << std::endl;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user