util: Introduce ToIntegral<T>(const std::string&) for locale independent parsing using std::from_chars(…) (C++17)

util: Avoid locale dependent functions strtol/strtoll/strtoul/strtoull in ParseInt32/ParseInt64/ParseUInt32/ParseUInt64

fuzz: Assert equivalence between new and old Parse{Int,Uint}{8,32,64} functions

test: Add unit tests for ToIntegral<T>(const std::string&)
This commit is contained in:
practicalswift
2021-09-18 04:30:30 +00:00
parent e69cbac628
commit 4747db8761
5 changed files with 270 additions and 74 deletions

View File

@@ -12,8 +12,10 @@
#include <attributes.h>
#include <span.h>
#include <charconv>
#include <cstdint>
#include <iterator>
#include <optional>
#include <string>
#include <vector>
@@ -94,6 +96,24 @@ constexpr inline bool IsSpace(char c) noexcept {
return c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v';
}
/**
* Convert string to integral type T.
*
* @returns std::nullopt if the entire string could not be parsed, or if the
* parsed value is not in the range representable by the type T.
*/
template <typename T>
std::optional<T> ToIntegral(const std::string& str)
{
static_assert(std::is_integral<T>::value);
T result;
const auto [first_nonmatching, error_condition] = std::from_chars(str.data(), str.data() + str.size(), result);
if (first_nonmatching != str.data() + str.size() || error_condition != std::errc{}) {
return std::nullopt;
}
return {result};
}
/**
* Convert string to signed 32-bit integer with strict parse error feedback.
* @returns true if the entire string could be parsed as valid integer,