diff --git a/ChangeLog b/ChangeLog index 7f1330b..8c11ec8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2024-07-17 Daniel Lemire + + * inst/include/RcppSimdJson/deserialize/scalar.hpp: guarded a call to std::string::erase + 2024-07-06 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Release 0.1.12 diff --git a/inst/include/RcppSimdJson/deserialize/scalar.hpp b/inst/include/RcppSimdJson/deserialize/scalar.hpp index 4c54f0e..a8fcdb0 100644 --- a/inst/include/RcppSimdJson/deserialize/scalar.hpp +++ b/inst/include/RcppSimdJson/deserialize/scalar.hpp @@ -91,8 +91,24 @@ get_scalar_(simdjson::dom::element element) noexcept(noxcp template <> inline auto get_scalar_(simdjson::dom::element element) noexcept(noxcpt()) { - auto out = std::to_string(double(element)); - out.erase(out.find_last_not_of('0') + 2, std::string::npos); + std::string out = std::to_string(double(element)); + // The previous code was as follows... + // out.erase(out.find_last_not_of('0') + 2, std::string::npos); + // This code effectively makes sure that we never end with more than one zero. + // E.g., 1.2000 becomes 1.20, but 1.000333333 remains 1.000333333. + // The problem of course, is that if you have 1.000333333, then you will + // do out.erase(10+2, std::string::npos) on a string of length 11. + // Per the C++ specification, you should get std::out_of_range if index > size(). + // + // We need to be more careful. + auto found = out.find_last_not_of('0'); + // check that a non-zero digit was found and that there are at least + // two zeros following it. + if (found != std::string::npos && found + 2 < out.size()) { + // at indexes found + 1, found + 2... are zeros, we keep + // just the one at found + 1 + out.erase(found + 2); + } return Rcpp::String(out); } // return double