#ifndef LLVM_SUPPORT_JSON_H
#define LLVM_SUPPORT_JSON_H
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/STLFunctionalExtras.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/raw_ostream.h"
#include <map>
namespace llvm {
namespace json {
bool isUTF8(llvm::StringRef S, size_t *ErrOffset = nullptr);
std::string fixUTF8(llvm::StringRef S);
class Array;
class ObjectKey;
class Value;
template <typename T> Value toJSON(const llvm::Optional<T> &Opt);
class Object {
using Storage = DenseMap<ObjectKey, Value, llvm::DenseMapInfo<StringRef>>;
Storage M;
public:
using key_type = ObjectKey;
using mapped_type = Value;
using value_type = Storage::value_type;
using iterator = Storage::iterator;
using const_iterator = Storage::const_iterator;
Object() = default;
struct KV;
explicit Object(std::initializer_list<KV> Properties);
iterator begin() { return M.begin(); }
const_iterator begin() const { return M.begin(); }
iterator end() { return M.end(); }
const_iterator end() const { return M.end(); }
bool empty() const { return M.empty(); }
size_t size() const { return M.size(); }
void clear() { M.clear(); }
std::pair<iterator, bool> insert(KV E);
template <typename... Ts>
std::pair<iterator, bool> try_emplace(const ObjectKey &K, Ts &&... Args) {
return M.try_emplace(K, std::forward<Ts>(Args)...);
}
template <typename... Ts>
std::pair<iterator, bool> try_emplace(ObjectKey &&K, Ts &&... Args) {
return M.try_emplace(std::move(K), std::forward<Ts>(Args)...);
}
bool erase(StringRef K);
void erase(iterator I) { M.erase(I); }
iterator find(StringRef K) { return M.find_as(K); }
const_iterator find(StringRef K) const { return M.find_as(K); }
Value &operator[](const ObjectKey &K);
Value &operator[](ObjectKey &&K);
Value *get(StringRef K);
const Value *get(StringRef K) const;
llvm::Optional<std::nullptr_t> getNull(StringRef K) const;
llvm::Optional<bool> getBoolean(StringRef K) const;
llvm::Optional<double> getNumber(StringRef K) const;
llvm::Optional<int64_t> getInteger(StringRef K) const;
llvm::Optional<llvm::StringRef> getString(StringRef K) const;
const json::Object *getObject(StringRef K) const;
json::Object *getObject(StringRef K);
const json::Array *getArray(StringRef K) const;
json::Array *getArray(StringRef K);
};
bool operator==(const Object &LHS, const Object &RHS);
inline bool operator!=(const Object &LHS, const Object &RHS) {
return !(LHS == RHS);
}
class Array {
std::vector<Value> V;
public:
using value_type = Value;
using iterator = std::vector<Value>::iterator;
using const_iterator = std::vector<Value>::const_iterator;
Array() = default;
explicit Array(std::initializer_list<Value> Elements);
template <typename Collection> explicit Array(const Collection &C) {
for (const auto &V : C)
emplace_back(V);
}
Value &operator[](size_t I);
const Value &operator[](size_t I) const;
Value &front();
const Value &front() const;
Value &back();
const Value &back() const;
Value *data();
const Value *data() const;
iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;
bool empty() const;
size_t size() const;
void reserve(size_t S);
void clear();
void push_back(const Value &E);
void push_back(Value &&E);
template <typename... Args> void emplace_back(Args &&...A);
void pop_back();
iterator insert(iterator P, const Value &E);
iterator insert(iterator P, Value &&E);
template <typename It> iterator insert(iterator P, It A, It Z);
template <typename... Args> iterator emplace(const_iterator P, Args &&...A);
friend bool operator==(const Array &L, const Array &R);
};
inline bool operator!=(const Array &L, const Array &R) { return !(L == R); }
class Value {
public:
enum Kind {
Null,
Boolean,
Number,
String,
Array,
Object,
};
Value(const Value &M) { copyFrom(M); }
Value(Value &&M) { moveFrom(std::move(M)); }
Value(std::initializer_list<Value> Elements);
Value(json::Array &&Elements) : Type(T_Array) {
create<json::Array>(std::move(Elements));
}
template <typename Elt>
Value(const std::vector<Elt> &C) : Value(json::Array(C)) {}
Value(json::Object &&Properties) : Type(T_Object) {
create<json::Object>(std::move(Properties));
}
template <typename Elt>
Value(const std::map<std::string, Elt> &C) : Value(json::Object(C)) {}
Value(std::string V) : Type(T_String) {
if (LLVM_UNLIKELY(!isUTF8(V))) {
assert(false && "Invalid UTF-8 in value used as JSON");
V = fixUTF8(std::move(V));
}
create<std::string>(std::move(V));
}
Value(const llvm::SmallVectorImpl<char> &V)
: Value(std::string(V.begin(), V.end())) {}
Value(const llvm::formatv_object_base &V) : Value(V.str()) {}
Value(StringRef V) : Type(T_StringRef) {
create<llvm::StringRef>(V);
if (LLVM_UNLIKELY(!isUTF8(V))) {
assert(false && "Invalid UTF-8 in value used as JSON");
*this = Value(fixUTF8(V));
}
}
Value(const char *V) : Value(StringRef(V)) {}
Value(std::nullptr_t) : Type(T_Null) {}
template <typename T,
typename = std::enable_if_t<std::is_same<T, bool>::value>,
bool = false>
Value(T B) : Type(T_Boolean) {
create<bool>(B);
}
template <typename T,
typename = std::enable_if_t<std::is_same<T, uint64_t>::value>,
bool = false, bool = false>
Value(T V) : Type(T_UINT64) {
create<uint64_t>(uint64_t{V});
}
template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>,
typename = std::enable_if_t<!std::is_same<T, bool>::value>,
typename = std::enable_if_t<!std::is_same<T, uint64_t>::value>>
Value(T I) : Type(T_Integer) {
create<int64_t>(int64_t{I});
}
template <typename T,
typename = std::enable_if_t<std::is_floating_point<T>::value>,
double * = nullptr>
Value(T D) : Type(T_Double) {
create<double>(double{D});
}
template <typename T,
typename = std::enable_if_t<std::is_same<
Value, decltype(toJSON(*(const T *)nullptr))>::value>,
Value * = nullptr>
Value(const T &V) : Value(toJSON(V)) {}
Value &operator=(const Value &M) {
destroy();
copyFrom(M);
return *this;
}
Value &operator=(Value &&M) {
destroy();
moveFrom(std::move(M));
return *this;
}
~Value() { destroy(); }
Kind kind() const {
switch (Type) {
case T_Null:
return Null;
case T_Boolean:
return Boolean;
case T_Double:
case T_Integer:
case T_UINT64:
return Number;
case T_String:
case T_StringRef:
return String;
case T_Object:
return Object;
case T_Array:
return Array;
}
llvm_unreachable("Unknown kind");
}
llvm::Optional<std::nullptr_t> getAsNull() const {
if (LLVM_LIKELY(Type == T_Null))
return nullptr;
return llvm::None;
}
llvm::Optional<bool> getAsBoolean() const {
if (LLVM_LIKELY(Type == T_Boolean))
return as<bool>();
return llvm::None;
}
llvm::Optional<double> getAsNumber() const {
if (LLVM_LIKELY(Type == T_Double))
return as<double>();
if (LLVM_LIKELY(Type == T_Integer))
return as<int64_t>();
if (LLVM_LIKELY(Type == T_UINT64))
return as<uint64_t>();
return llvm::None;
}
llvm::Optional<int64_t> getAsInteger() const {
if (LLVM_LIKELY(Type == T_Integer))
return as<int64_t>();
if (LLVM_LIKELY(Type == T_Double)) {
double D = as<double>();
if (LLVM_LIKELY(std::modf(D, &D) == 0.0 &&
D >= double(std::numeric_limits<int64_t>::min()) &&
D <= double(std::numeric_limits<int64_t>::max())))
return D;
}
return llvm::None;
}
llvm::Optional<uint64_t> getAsUINT64() const {
if (Type == T_UINT64)
return as<uint64_t>();
else if (Type == T_Integer) {
int64_t N = as<int64_t>();
if (N >= 0)
return as<uint64_t>();
}
return llvm::None;
}
llvm::Optional<llvm::StringRef> getAsString() const {
if (Type == T_String)
return llvm::StringRef(as<std::string>());
if (LLVM_LIKELY(Type == T_StringRef))
return as<llvm::StringRef>();
return llvm::None;
}
const json::Object *getAsObject() const {
return LLVM_LIKELY(Type == T_Object) ? &as<json::Object>() : nullptr;
}
json::Object *getAsObject() {
return LLVM_LIKELY(Type == T_Object) ? &as<json::Object>() : nullptr;
}
const json::Array *getAsArray() const {
return LLVM_LIKELY(Type == T_Array) ? &as<json::Array>() : nullptr;
}
json::Array *getAsArray() {
return LLVM_LIKELY(Type == T_Array) ? &as<json::Array>() : nullptr;
}
private:
void destroy();
void copyFrom(const Value &M);
void moveFrom(const Value &&M);
friend class Array;
friend class Object;
template <typename T, typename... U> void create(U &&... V) {
new (reinterpret_cast<T *>(&Union)) T(std::forward<U>(V)...);
}
template <typename T> T &as() const {
void *Storage = static_cast<void *>(&Union);
return *static_cast<T *>(Storage);
}
friend class OStream;
enum ValueType : char16_t {
T_Null,
T_Boolean,
T_Double,
T_Integer,
T_UINT64,
T_StringRef,
T_String,
T_Object,
T_Array,
};
mutable ValueType Type;
mutable llvm::AlignedCharArrayUnion<bool, double, int64_t, uint64_t,
llvm::StringRef, std::string, json::Array,
json::Object>
Union;
friend bool operator==(const Value &, const Value &);
};
bool operator==(const Value &, const Value &);
inline bool operator!=(const Value &L, const Value &R) { return !(L == R); }
inline Value &Array::operator[](size_t I) { return V[I]; }
inline const Value &Array::operator[](size_t I) const { return V[I]; }
inline Value &Array::front() { return V.front(); }
inline const Value &Array::front() const { return V.front(); }
inline Value &Array::back() { return V.back(); }
inline const Value &Array::back() const { return V.back(); }
inline Value *Array::data() { return V.data(); }
inline const Value *Array::data() const { return V.data(); }
inline typename Array::iterator Array::begin() { return V.begin(); }
inline typename Array::const_iterator Array::begin() const { return V.begin(); }
inline typename Array::iterator Array::end() { return V.end(); }
inline typename Array::const_iterator Array::end() const { return V.end(); }
inline bool Array::empty() const { return V.empty(); }
inline size_t Array::size() const { return V.size(); }
inline void Array::reserve(size_t S) { V.reserve(S); }
inline void Array::clear() { V.clear(); }
inline void Array::push_back(const Value &E) { V.push_back(E); }
inline void Array::push_back(Value &&E) { V.push_back(std::move(E)); }
template <typename... Args> inline void Array::emplace_back(Args &&...A) {
V.emplace_back(std::forward<Args>(A)...);
}
inline void Array::pop_back() { V.pop_back(); }
inline typename Array::iterator Array::insert(iterator P, const Value &E) {
return V.insert(P, E);
}
inline typename Array::iterator Array::insert(iterator P, Value &&E) {
return V.insert(P, std::move(E));
}
template <typename It>
inline typename Array::iterator Array::insert(iterator P, It A, It Z) {
return V.insert(P, A, Z);
}
template <typename... Args>
inline typename Array::iterator Array::emplace(const_iterator P, Args &&...A) {
return V.emplace(P, std::forward<Args>(A)...);
}
inline bool operator==(const Array &L, const Array &R) { return L.V == R.V; }
class ObjectKey {
public:
ObjectKey(const char *S) : ObjectKey(StringRef(S)) {}
ObjectKey(std::string S) : Owned(new std::string(std::move(S))) {
if (LLVM_UNLIKELY(!isUTF8(*Owned))) {
assert(false && "Invalid UTF-8 in value used as JSON");
*Owned = fixUTF8(std::move(*Owned));
}
Data = *Owned;
}
ObjectKey(llvm::StringRef S) : Data(S) {
if (LLVM_UNLIKELY(!isUTF8(Data))) {
assert(false && "Invalid UTF-8 in value used as JSON");
*this = ObjectKey(fixUTF8(S));
}
}
ObjectKey(const llvm::SmallVectorImpl<char> &V)
: ObjectKey(std::string(V.begin(), V.end())) {}
ObjectKey(const llvm::formatv_object_base &V) : ObjectKey(V.str()) {}
ObjectKey(const ObjectKey &C) { *this = C; }
ObjectKey(ObjectKey &&C) : ObjectKey(static_cast<const ObjectKey &&>(C)) {}
ObjectKey &operator=(const ObjectKey &C) {
if (C.Owned) {
Owned.reset(new std::string(*C.Owned));
Data = *Owned;
} else {
Data = C.Data;
}
return *this;
}
ObjectKey &operator=(ObjectKey &&) = default;
operator llvm::StringRef() const { return Data; }
std::string str() const { return Data.str(); }
private:
std::unique_ptr<std::string> Owned;
llvm::StringRef Data;
};
inline bool operator==(const ObjectKey &L, const ObjectKey &R) {
return llvm::StringRef(L) == llvm::StringRef(R);
}
inline bool operator!=(const ObjectKey &L, const ObjectKey &R) {
return !(L == R);
}
inline bool operator<(const ObjectKey &L, const ObjectKey &R) {
return StringRef(L) < StringRef(R);
}
struct Object::KV {
ObjectKey K;
Value V;
};
inline Object::Object(std::initializer_list<KV> Properties) {
for (const auto &P : Properties) {
auto R = try_emplace(P.K, nullptr);
if (R.second)
R.first->getSecond().moveFrom(std::move(P.V));
}
}
inline std::pair<Object::iterator, bool> Object::insert(KV E) {
return try_emplace(std::move(E.K), std::move(E.V));
}
inline bool Object::erase(StringRef K) {
return M.erase(ObjectKey(K));
}
class Path {
public:
class Root;
void report(llvm::StringLiteral Message);
Path(Root &R) : Parent(nullptr), Seg(&R) {}
Path index(unsigned Index) const { return Path(this, Segment(Index)); }
Path field(StringRef Field) const { return Path(this, Segment(Field)); }
private:
class Segment {
uintptr_t Pointer;
unsigned Offset;
public:
Segment() = default;
Segment(Root *R) : Pointer(reinterpret_cast<uintptr_t>(R)) {}
Segment(llvm::StringRef Field)
: Pointer(reinterpret_cast<uintptr_t>(Field.data())),
Offset(static_cast<unsigned>(Field.size())) {}
Segment(unsigned Index) : Pointer(0), Offset(Index) {}
bool isField() const { return Pointer != 0; }
StringRef field() const {
return StringRef(reinterpret_cast<const char *>(Pointer), Offset);
}
unsigned index() const { return Offset; }
Root *root() const { return reinterpret_cast<Root *>(Pointer); }
};
const Path *Parent;
Segment Seg;
Path(const Path *Parent, Segment S) : Parent(Parent), Seg(S) {}
};
class Path::Root {
llvm::StringRef Name;
llvm::StringLiteral ErrorMessage;
std::vector<Path::Segment> ErrorPath;
friend void Path::report(llvm::StringLiteral Message);
public:
Root(llvm::StringRef Name = "") : Name(Name), ErrorMessage("") {}
Root(Root &&) = delete;
Root &operator=(Root &&) = delete;
Root(const Root &) = delete;
Root &operator=(const Root &) = delete;
Error getError() const;
void printErrorContext(const Value &, llvm::raw_ostream &) const;
};
inline bool fromJSON(const Value &E, std::string &Out, Path P) {
if (auto S = E.getAsString()) {
Out = std::string(*S);
return true;
}
P.report("expected string");
return false;
}
inline bool fromJSON(const Value &E, int &Out, Path P) {
if (auto S = E.getAsInteger()) {
Out = *S;
return true;
}
P.report("expected integer");
return false;
}
inline bool fromJSON(const Value &E, int64_t &Out, Path P) {
if (auto S = E.getAsInteger()) {
Out = *S;
return true;
}
P.report("expected integer");
return false;
}
inline bool fromJSON(const Value &E, double &Out, Path P) {
if (auto S = E.getAsNumber()) {
Out = *S;
return true;
}
P.report("expected number");
return false;
}
inline bool fromJSON(const Value &E, bool &Out, Path P) {
if (auto S = E.getAsBoolean()) {
Out = *S;
return true;
}
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;
return true;
}
P.report("expected null");
return false;
}
template <typename T>
bool fromJSON(const Value &E, llvm::Optional<T> &Out, Path P) {
if (E.getAsNull()) {
Out = llvm::None;
return true;
}
T Result;
if (!fromJSON(E, Result, P))
return false;
Out = std::move(Result);
return true;
}
template <typename T>
bool fromJSON(const Value &E, std::vector<T> &Out, Path P) {
if (auto *A = E.getAsArray()) {
Out.clear();
Out.resize(A->size());
for (size_t I = 0; I < A->size(); ++I)
if (!fromJSON((*A)[I], Out[I], P.index(I)))
return false;
return true;
}
P.report("expected array");
return false;
}
template <typename T>
bool fromJSON(const Value &E, std::map<std::string, T> &Out, Path P) {
if (auto *O = E.getAsObject()) {
Out.clear();
for (const auto &KV : *O)
if (!fromJSON(KV.second, Out[std::string(llvm::StringRef(KV.first))],
P.field(KV.first)))
return false;
return true;
}
P.report("expected object");
return false;
}
template <typename T> Value toJSON(const llvm::Optional<T> &Opt) {
return Opt ? Value(*Opt) : Value(nullptr);
}
class ObjectMapper {
public:
ObjectMapper(const Value &E, Path P) : O(E.getAsObject()), P(P) {
if (!O)
P.report("expected object");
}
operator bool() const { return O; }
template <typename T> bool map(StringLiteral Prop, T &Out) {
assert(*this && "Must check this is an object before calling map()");
if (const Value *E = O->get(Prop))
return fromJSON(*E, Out, P.field(Prop));
P.field(Prop).report("missing value");
return false;
}
template <typename T> bool map(StringLiteral Prop, llvm::Optional<T> &Out) {
assert(*this && "Must check this is an object before calling map()");
if (const Value *E = O->get(Prop))
return fromJSON(*E, Out, P.field(Prop));
Out = llvm::None;
return true;
}
template <typename T> bool mapOptional(StringLiteral Prop, T &Out) {
assert(*this && "Must check this is an object before calling map()");
if (const Value *E = O->get(Prop))
return fromJSON(*E, Out, P.field(Prop));
return true;
}
private:
const Object *O;
Path P;
};
llvm::Expected<Value> parse(llvm::StringRef JSON);
class ParseError : public llvm::ErrorInfo<ParseError> {
const char *Msg;
unsigned Line, Column, Offset;
public:
static char ID;
ParseError(const char *Msg, unsigned Line, unsigned Column, unsigned Offset)
: Msg(Msg), Line(Line), Column(Column), Offset(Offset) {}
void log(llvm::raw_ostream &OS) const override {
OS << llvm::formatv("[{0}:{1}, byte={2}]: {3}", Line, Column, Offset, Msg);
}
std::error_code convertToErrorCode() const override {
return llvm::inconvertibleErrorCode();
}
};
template <typename T>
Expected<T> parse(const llvm::StringRef &JSON, const char *RootName = "") {
auto V = parse(JSON);
if (!V)
return V.takeError();
Path::Root R(RootName);
T Result;
if (fromJSON(*V, Result, R))
return std::move(Result);
return R.getError();
}
class OStream {
public:
using Block = llvm::function_ref<void()>;
explicit OStream(llvm::raw_ostream &OS, unsigned IndentSize = 0)
: OS(OS), IndentSize(IndentSize) {
Stack.emplace_back();
}
~OStream() {
assert(Stack.size() == 1 && "Unmatched begin()/end()");
assert(Stack.back().Ctx == Singleton);
assert(Stack.back().HasValue && "Did not write top-level value");
}
void flush() { OS.flush(); }
void value(const Value &V);
void array(Block Contents) {
arrayBegin();
Contents();
arrayEnd();
}
void object(Block Contents) {
objectBegin();
Contents();
objectEnd();
}
void rawValue(llvm::function_ref<void(raw_ostream &)> Contents) {
rawValueBegin();
Contents(OS);
rawValueEnd();
}
void rawValue(llvm::StringRef Contents) {
rawValue([&](raw_ostream &OS) { OS << Contents; });
}
void comment(llvm::StringRef);
void attribute(llvm::StringRef Key, const Value& Contents) {
attributeImpl(Key, [&] { value(Contents); });
}
void attributeArray(llvm::StringRef Key, Block Contents) {
attributeImpl(Key, [&] { array(Contents); });
}
void attributeObject(llvm::StringRef Key, Block Contents) {
attributeImpl(Key, [&] { object(Contents); });
}
void arrayBegin();
void arrayEnd();
void objectBegin();
void objectEnd();
void attributeBegin(llvm::StringRef Key);
void attributeEnd();
raw_ostream &rawValueBegin();
void rawValueEnd();
private:
void attributeImpl(llvm::StringRef Key, Block Contents) {
attributeBegin(Key);
Contents();
attributeEnd();
}
void valueBegin();
void flushComment();
void newline();
enum Context {
Singleton, Array,
Object,
RawValue, };
struct State {
Context Ctx = Singleton;
bool HasValue = false;
};
llvm::SmallVector<State, 16> Stack; llvm::StringRef PendingComment;
llvm::raw_ostream &OS;
unsigned IndentSize;
unsigned Indent = 0;
};
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Value &V) {
OStream(OS).value(V);
return OS;
}
}
template <> struct format_provider<llvm::json::Value> {
static void format(const llvm::json::Value &, raw_ostream &, StringRef);
};
}
#endif