summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Support/JSON.cpp
diff options
context:
space:
mode:
authorSam McCall <sam.mccall@gmail.com>2018-07-09 12:16:40 +0000
committerSam McCall <sam.mccall@gmail.com>2018-07-09 12:16:40 +0000
commitd93eaeb7c399488b16753b1786a30ec6a59761c7 (patch)
tree67793aef0e29ef86851aee92b0f0c1cdc018240e /llvm/lib/Support/JSON.cpp
parent6f33b330ae1808ab2a5d7184abafefc5d5821059 (diff)
downloadbcm5719-llvm-d93eaeb7c399488b16753b1786a30ec6a59761c7.tar.gz
bcm5719-llvm-d93eaeb7c399488b16753b1786a30ec6a59761c7.zip
[Support] Make JSON handle doubles and int64s losslessly
Summary: This patch adds a new "integer" ValueType, and renames Number -> Double. This allows us to preserve the full precision of int64_t when parsing integers from the wire, or constructing from an integer. The API is unchanged, other than giving asInteger() a clearer contract. In addition, always output doubles with enough precision that parsing will reconstruct the same double. Reviewers: simon_tatham Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D46209 llvm-svn: 336541
Diffstat (limited to 'llvm/lib/Support/JSON.cpp')
-rw-r--r--llvm/lib/Support/JSON.cpp42
1 files changed, 26 insertions, 16 deletions
diff --git a/llvm/lib/Support/JSON.cpp b/llvm/lib/Support/JSON.cpp
index 0371d1ab251..c2025bb2299 100644
--- a/llvm/lib/Support/JSON.cpp
+++ b/llvm/lib/Support/JSON.cpp
@@ -104,7 +104,8 @@ void Value::copyFrom(const Value &M) {
switch (Type) {
case T_Null:
case T_Boolean:
- case T_Number:
+ case T_Double:
+ case T_Integer:
memcpy(Union.buffer, M.Union.buffer, sizeof(Union.buffer));
break;
case T_StringRef:
@@ -127,7 +128,8 @@ void Value::moveFrom(const Value &&M) {
switch (Type) {
case T_Null:
case T_Boolean:
- case T_Number:
+ case T_Double:
+ case T_Integer:
memcpy(Union.buffer, M.Union.buffer, sizeof(Union.buffer));
break;
case T_StringRef:
@@ -152,7 +154,8 @@ void Value::destroy() {
switch (Type) {
case T_Null:
case T_Boolean:
- case T_Number:
+ case T_Double:
+ case T_Integer:
break;
case T_StringRef:
as<StringRef>().~StringRef();
@@ -217,7 +220,7 @@ private:
}
// On invalid syntax, parseX() functions return false and set Err.
- bool parseNumber(char First, double &Out);
+ bool parseNumber(char First, Value &Out);
bool parseString(std::string &Out);
bool parseUnicode(std::string &Out);
bool parseError(const char *Msg); // always returns false
@@ -317,25 +320,28 @@ bool Parser::parseValue(Value &Out) {
}
}
default:
- if (isNumber(C)) {
- double Num;
- if (parseNumber(C, Num)) {
- Out = Num;
- return true;
- } else {
- return false;
- }
- }
+ if (isNumber(C))
+ return parseNumber(C, Out);
return parseError("Invalid JSON value");
}
}
-bool Parser::parseNumber(char First, double &Out) {
+bool Parser::parseNumber(char First, Value &Out) {
+ // Read the number into a string. (Must be null-terminated for strto*).
SmallString<24> S;
S.push_back(First);
while (isNumber(peek()))
S.push_back(next());
char *End;
+ // Try first to parse as integer, and if so preserve full 64 bits.
+ // strtoll returns long long >= 64 bits, so check it's in range too.
+ auto I = std::strtoll(S.c_str(), &End, 10);
+ if (End == S.end() && I >= std::numeric_limits<int64_t>::min() &&
+ I <= std::numeric_limits<int64_t>::max()) {
+ Out = int64_t(I);
+ return true;
+ }
+ // If it's not an integer
Out = std::strtod(S.c_str(), &End);
return End == S.end() || parseError("Invalid JSON value (number?)");
}
@@ -558,8 +564,12 @@ void llvm::json::Value::print(raw_ostream &OS, const Indenter &I) const {
case T_Boolean:
OS << (as<bool>() ? "true" : "false");
break;
- case T_Number:
- OS << format("%g", as<double>());
+ case T_Double:
+ OS << format("%.*g", std::numeric_limits<double>::max_digits10,
+ as<double>());
+ break;
+ case T_Integer:
+ OS << as<int64_t>();
break;
case T_StringRef:
quote(OS, as<StringRef>());
OpenPOWER on IntegriCloud