+Expected<Tgt, ConversionCode> str_to_floating(StringPiece* src) noexcept {
+ using namespace double_conversion;
+ static StringToDoubleConverter
+ conv(StringToDoubleConverter::ALLOW_TRAILING_JUNK
+ | StringToDoubleConverter::ALLOW_LEADING_SPACES,
+ 0.0,
+ // return this for junk input string
+ std::numeric_limits<double>::quiet_NaN(),
+ nullptr, nullptr);
+
+ if (src->empty()) {
+ return makeUnexpected(ConversionCode::EMPTY_INPUT_STRING);
+ }
+
+ int length;
+ auto result = conv.StringToDouble(src->data(),
+ static_cast<int>(src->size()),
+ &length); // processed char count
+
+ if (!std::isnan(result)) {
+ // If we get here with length = 0, the input string is empty.
+ // If we get here with result = 0.0, it's either because the string
+ // contained only whitespace, or because we had an actual zero value
+ // (with potential trailing junk). If it was only whitespace, we
+ // want to raise an error; length will point past the last character
+ // that was processed, so we need to check if that character was
+ // whitespace or not.
+ if (length == 0 ||
+ (result == 0.0 && std::isspace((*src)[size_t(length) - 1]))) {
+ return makeUnexpected(ConversionCode::EMPTY_INPUT_STRING);
+ }
+ src->advance(size_t(length));
+ return Tgt(result);
+ }
+
+ auto* e = src->end();
+ auto* b =
+ std::find_if_not(src->begin(), e, [](char c) { return std::isspace(c); });
+
+ // There must be non-whitespace, otherwise we would have caught this above
+ assert(b < e);
+ size_t size = size_t(e - b);
+
+ bool negative = false;
+ if (*b == '-') {
+ negative = true;
+ ++b;
+ --size;
+ }
+
+ result = 0.0;
+
+ switch (tolower_ascii(*b)) {
+ case 'i':
+ if (size >= 3 && tolower_ascii(b[1]) == 'n' &&
+ tolower_ascii(b[2]) == 'f') {
+ if (size >= 8 && tolower_ascii(b[3]) == 'i' &&
+ tolower_ascii(b[4]) == 'n' && tolower_ascii(b[5]) == 'i' &&
+ tolower_ascii(b[6]) == 't' && tolower_ascii(b[7]) == 'y') {
+ b += 8;
+ } else {
+ b += 3;
+ }
+ result = std::numeric_limits<Tgt>::infinity();
+ }
+ break;
+
+ case 'n':
+ if (size >= 3 && tolower_ascii(b[1]) == 'a' &&
+ tolower_ascii(b[2]) == 'n') {
+ b += 3;
+ result = std::numeric_limits<Tgt>::quiet_NaN();
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (result == 0.0) {
+ // All bets are off
+ return makeUnexpected(ConversionCode::STRING_TO_FLOAT_ERROR);
+ }
+
+ if (negative) {
+ result = -result;
+ }
+
+ src->assign(b, e);
+
+ return Tgt(result);
+}
+
+template Expected<float, ConversionCode> str_to_floating<float>(
+ StringPiece* src) noexcept;
+template Expected<double, ConversionCode> str_to_floating<double>(
+ StringPiece* src) noexcept;
+
+/**
+ * This class takes care of additional processing needed for signed values,
+ * like leading sign character and overflow checks.
+ */
+template <typename T, bool IsSigned = std::is_signed<T>::value>
+class SignedValueHandler;
+
+template <typename T>
+class SignedValueHandler<T, true> {
+ public:
+ ConversionCode init(const char*& b) {
+ negative_ = false;
+ if (!std::isdigit(*b)) {
+ if (*b == '-') {
+ negative_ = true;
+ } else if (UNLIKELY(*b != '+')) {
+ return ConversionCode::INVALID_LEADING_CHAR;
+ }
+ ++b;
+ }
+ return ConversionCode::SUCCESS;
+ }
+
+ ConversionCode overflow() {
+ return negative_ ? ConversionCode::NEGATIVE_OVERFLOW
+ : ConversionCode::POSITIVE_OVERFLOW;
+ }
+
+ template <typename U>
+ Expected<T, ConversionCode> finalize(U value) {
+ T rv;
+ if (negative_) {
+ rv = T(-value);
+ if (UNLIKELY(rv > 0)) {
+ return makeUnexpected(ConversionCode::NEGATIVE_OVERFLOW);
+ }
+ } else {
+ rv = T(value);
+ if (UNLIKELY(rv < 0)) {
+ return makeUnexpected(ConversionCode::POSITIVE_OVERFLOW);
+ }
+ }
+ return rv;
+ }