}
auto const wasE = *in == 'e' || *in == 'E';
+
+ constexpr const char* maxInt = "9223372036854775807";
+ constexpr const char* minInt = "9223372036854775808";
+ constexpr auto maxIntLen = __builtin_strlen(maxInt);
+
if (*in != '.' && !wasE) {
- auto val = to<int64_t>(integral);
- in.skipWhitespace();
- return val;
+ if (LIKELY(!in.getOpts().double_fallback || integral.size() < maxIntLen) ||
+ (integral.size() == maxIntLen &&
+ (integral <= maxInt || (integral == minInt && negative)))) {
+ auto val = to<int64_t>(integral);
+ in.skipWhitespace();
+ return val;
+ } else {
+ auto val = to<double>(integral);
+ in.skipWhitespace();
+ return val;
+ }
}
auto end = !wasE ? (++in, in.skipDigits().end()) : in.begin();
, allow_nan_inf(false)
, double_mode(double_conversion::DoubleToStringConverter::SHORTEST)
, double_num_digits(0) // ignored when mode is SHORTEST
+ , double_fallback(false)
{}
// If true, keys in an object can be non-strings. (In strict
// toAppend implementation for floating point for more info
double_conversion::DoubleToStringConverter::DtoaMode double_mode;
unsigned int double_num_digits;
+
+ // Fallback to double when a value that looks like integer is too big to
+ // fit in an int64_t. Can result in loss a of precision.
+ bool double_fallback;
};
/*
EXPECT_EQ(1.5, dval.items().begin()->first.asDouble());
}
+TEST(Json, ParseDoubleFallback) {
+ // default behavior
+ EXPECT_THROW(parseJson("{\"a\":847605071342477600000000000000}"),
+ std::range_error);
+ EXPECT_THROW(parseJson("{\"a\":-9223372036854775809}"),
+ std::range_error);
+ EXPECT_THROW(parseJson("{\"a\":9223372036854775808}"),
+ std::range_error);
+ EXPECT_EQ(std::numeric_limits<int64_t>::min(),
+ parseJson("{\"a\":-9223372036854775808}").items().begin()
+ ->second.asInt());
+ EXPECT_EQ(std::numeric_limits<int64_t>::max(),
+ parseJson("{\"a\":9223372036854775807}").items().begin()->second.asInt());
+ // with double_fallback
+ folly::json::serialization_opts opts;
+ opts.double_fallback = true;
+ EXPECT_EQ(847605071342477600000000000000.0,
+ parseJson("{\"a\":847605071342477600000000000000}",
+ opts).items().begin()->second.asDouble());
+ EXPECT_EQ(847605071342477600000000000000.0,
+ parseJson("{\"a\": 847605071342477600000000000000}",
+ opts).items().begin()->second.asDouble());
+ EXPECT_EQ(847605071342477600000000000000.0,
+ parseJson("{\"a\":847605071342477600000000000000 }",
+ opts).items().begin()->second.asDouble());
+ EXPECT_EQ(847605071342477600000000000000.0,
+ parseJson("{\"a\": 847605071342477600000000000000 }",
+ opts).items().begin()->second.asDouble());
+ EXPECT_EQ(std::numeric_limits<int64_t>::min(),
+ parseJson("{\"a\":-9223372036854775808}",
+ opts).items().begin()->second.asInt());
+ EXPECT_EQ(std::numeric_limits<int64_t>::max(),
+ parseJson("{\"a\":9223372036854775807}",
+ opts).items().begin()->second.asInt());
+ // show that some precision gets lost
+ EXPECT_EQ(847605071342477612345678900000.0,
+ parseJson("{\"a\":847605071342477612345678912345}",
+ opts).items().begin()->second.asDouble());
+}
+
TEST(Json, SortKeys) {
folly::json::serialization_opts opts_on, opts_off;
opts_on.sort_keys = true;