diff --git a/llvm/include/llvm/Support/JSON.h b/llvm/include/llvm/Support/JSON.h --- a/llvm/include/llvm/Support/JSON.h +++ b/llvm/include/llvm/Support/JSON.h @@ -234,7 +234,7 @@ /// Each Value is one of the JSON kinds: /// null (nullptr_t) /// boolean (bool) -/// number (double or int64) +/// number (double, int64 or uint64) /// string (StringRef) /// array (json::Array) /// object (json::Object) @@ -342,9 +342,20 @@ Value(T B) : Type(T_Boolean) { create(B); } - // Integers (except boolean). Must be non-narrowing convertible to int64_t. + + // Unsigned 64-bit long integers. + template ::value>, + bool = false, bool = false> + Value(T V) : Type(T_UINT64) { + create(uint64_t{V}); + } + + // Integers (except boolean and uint64_t). + // Must be non-narrowing convertible to int64_t. template ::value>, - typename = std::enable_if_t::value>> + typename = std::enable_if_t::value>, + typename = std::enable_if_t::value>> Value(T I) : Type(T_Integer) { create(int64_t{I}); } @@ -382,6 +393,7 @@ return Boolean; case T_Double: case T_Integer: + case T_UINT64: return Number; case T_String: case T_StringRef: @@ -410,6 +422,8 @@ return as(); if (LLVM_LIKELY(Type == T_Integer)) return as(); + if (LLVM_LIKELY(Type == T_UINT64)) + return as(); return llvm::None; } // Succeeds if the Value is a Number, and exactly representable as int64_t. @@ -425,6 +439,16 @@ } return llvm::None; } + llvm::Optional getAsUINT64() const { + if (Type == T_UINT64) + return as(); + else if (Type == T_Integer) { + int64_t N = as(); + if (N >= 0) + return as(); + } + return llvm::None; + } llvm::Optional getAsString() const { if (Type == T_String) return llvm::StringRef(as()); @@ -467,11 +491,12 @@ friend class OStream; - enum ValueType : char { + enum ValueType : char16_t { T_Null, T_Boolean, T_Double, T_Integer, + T_UINT64, T_StringRef, T_String, T_Object, @@ -479,8 +504,9 @@ }; // All members mutable, see moveFrom(). mutable ValueType Type; - mutable llvm::AlignedCharArrayUnion + mutable llvm::AlignedCharArrayUnion Union; friend bool operator==(const Value &, const Value &); }; @@ -683,6 +709,14 @@ P.report("expected boolean"); return false; } +inline bool fromJSON(const Value &E, uint64_t &Out, Path P) { + if (auto S = E.getAsUINT64()) { + Out = *S; + return true; + } + P.report("expected uint64_t"); + return false; +} inline bool fromJSON(const Value &E, std::nullptr_t &Out, Path P) { if (auto S = E.getAsNull()) { Out = *S; diff --git a/llvm/lib/Support/JSON.cpp b/llvm/lib/Support/JSON.cpp --- a/llvm/lib/Support/JSON.cpp +++ b/llvm/lib/Support/JSON.cpp @@ -109,6 +109,7 @@ case T_Boolean: case T_Double: case T_Integer: + case T_UINT64: memcpy(&Union, &M.Union, sizeof(Union)); break; case T_StringRef: @@ -133,6 +134,7 @@ case T_Boolean: case T_Double: case T_Integer: + case T_UINT64: memcpy(&Union, &M.Union, sizeof(Union)); break; case T_StringRef: @@ -159,6 +161,7 @@ case T_Boolean: case T_Double: case T_Integer: + case T_UINT64: break; case T_StringRef: as().~StringRef(); @@ -750,6 +753,8 @@ valueBegin(); if (V.Type == Value::T_Integer) OS << *V.getAsInteger(); + else if (V.Type == Value::T_UINT64) + OS << *V.getAsUINT64(); else OS << format("%.*g", std::numeric_limits::max_digits10, *V.getAsNumber()); diff --git a/llvm/unittests/Support/JSONTest.cpp b/llvm/unittests/Support/JSONTest.cpp --- a/llvm/unittests/Support/JSONTest.cpp +++ b/llvm/unittests/Support/JSONTest.cpp @@ -356,6 +356,27 @@ } } +// Verify uint64_t type. +TEST(JSONTest, U64Integers) { + Value Val = uint64_t{3100100100}; + uint64_t Var = 3100100100; + EXPECT_EQ(Val, Var); + + // Test the parse() part. + const char *Str = "4611686018427387905"; + llvm::Expected Doc = parse(Str); + + EXPECT_TRUE(!!Doc); + EXPECT_EQ(Doc->getAsInteger(), int64_t{4611686018427387905}); + EXPECT_EQ(Doc->getAsUINT64(), uint64_t{4611686018427387905}); + + const char *Str2 = "-78278238238328222"; + llvm::Expected Doc2 = parse(Str2); + EXPECT_TRUE(!!Doc2); + EXPECT_EQ(Doc2->getAsInteger(), int64_t{-78278238238328222}); + EXPECT_EQ(Doc2->getAsUINT64(), llvm::None); +} + // Sample struct with typical JSON-mapping rules. struct CustomStruct { CustomStruct() : B(false) {}