blob: c1d136db1c2ef02c1144e0dd480c8ada93d4bebd [file] [log] [blame]
//===-- StructuredData.h ----------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLDB_UTILITY_STRUCTUREDDATA_H
#define LLDB_UTILITY_STRUCTUREDDATA_H
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/JSON.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/Stream.h"
#include "lldb/lldb-enumerations.h"
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <map>
#include <memory>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
namespace lldb_private {
class Status;
}
namespace lldb_private {
/// \class StructuredData StructuredData.h "lldb/Utility/StructuredData.h"
/// A class which can hold structured data
///
/// The StructuredData class is designed to hold the data from a JSON or plist
/// style file -- a serialized data structure with dictionaries (maps,
/// hashes), arrays, and concrete values like integers, floating point
/// numbers, strings, booleans.
///
/// StructuredData does not presuppose any knowledge of the schema for the
/// data it is holding; it can parse JSON data, for instance, and other parts
/// of lldb can iterate through the parsed data set to find keys and values
/// that may be present.
class StructuredData {
public:
class Object;
class Array;
class Integer;
class Float;
class Boolean;
class String;
class Dictionary;
class Generic;
typedef std::shared_ptr<Object> ObjectSP;
typedef std::shared_ptr<Array> ArraySP;
typedef std::shared_ptr<Integer> IntegerSP;
typedef std::shared_ptr<Float> FloatSP;
typedef std::shared_ptr<Boolean> BooleanSP;
typedef std::shared_ptr<String> StringSP;
typedef std::shared_ptr<Dictionary> DictionarySP;
typedef std::shared_ptr<Generic> GenericSP;
class Object : public std::enable_shared_from_this<Object> {
public:
Object(lldb::StructuredDataType t = lldb::eStructuredDataTypeInvalid)
: m_type(t) {}
virtual ~Object() = default;
virtual bool IsValid() const { return true; }
virtual void Clear() { m_type = lldb::eStructuredDataTypeInvalid; }
lldb::StructuredDataType GetType() const { return m_type; }
void SetType(lldb::StructuredDataType t) { m_type = t; }
Array *GetAsArray() {
return ((m_type == lldb::eStructuredDataTypeArray)
? static_cast<Array *>(this)
: nullptr);
}
Dictionary *GetAsDictionary() {
return ((m_type == lldb::eStructuredDataTypeDictionary)
? static_cast<Dictionary *>(this)
: nullptr);
}
Integer *GetAsInteger() {
return ((m_type == lldb::eStructuredDataTypeInteger)
? static_cast<Integer *>(this)
: nullptr);
}
uint64_t GetIntegerValue(uint64_t fail_value = 0) {
Integer *integer = GetAsInteger();
return ((integer != nullptr) ? integer->GetValue() : fail_value);
}
Float *GetAsFloat() {
return ((m_type == lldb::eStructuredDataTypeFloat)
? static_cast<Float *>(this)
: nullptr);
}
double GetFloatValue(double fail_value = 0.0) {
Float *f = GetAsFloat();
return ((f != nullptr) ? f->GetValue() : fail_value);
}
Boolean *GetAsBoolean() {
return ((m_type == lldb::eStructuredDataTypeBoolean)
? static_cast<Boolean *>(this)
: nullptr);
}
bool GetBooleanValue(bool fail_value = false) {
Boolean *b = GetAsBoolean();
return ((b != nullptr) ? b->GetValue() : fail_value);
}
String *GetAsString() {
return ((m_type == lldb::eStructuredDataTypeString)
? static_cast<String *>(this)
: nullptr);
}
llvm::StringRef GetStringValue(const char *fail_value = nullptr) {
String *s = GetAsString();
if (s)
return s->GetValue();
return fail_value;
}
Generic *GetAsGeneric() {
return ((m_type == lldb::eStructuredDataTypeGeneric)
? static_cast<Generic *>(this)
: nullptr);
}
ObjectSP GetObjectForDotSeparatedPath(llvm::StringRef path);
void DumpToStdout(bool pretty_print = true) const;
virtual void Serialize(llvm::json::OStream &s) const = 0;
void Dump(lldb_private::Stream &s, bool pretty_print = true) const {
llvm::json::OStream jso(s.AsRawOstream(), pretty_print ? 2 : 0);
Serialize(jso);
}
private:
lldb::StructuredDataType m_type;
};
class Array : public Object {
public:
Array() : Object(lldb::eStructuredDataTypeArray) {}
~Array() override = default;
bool
ForEach(std::function<bool(Object *object)> const &foreach_callback) const {
for (const auto &object_sp : m_items) {
if (!foreach_callback(object_sp.get()))
return false;
}
return true;
}
size_t GetSize() const { return m_items.size(); }
ObjectSP operator[](size_t idx) {
if (idx < m_items.size())
return m_items[idx];
return ObjectSP();
}
ObjectSP GetItemAtIndex(size_t idx) const {
assert(idx < GetSize());
if (idx < m_items.size())
return m_items[idx];
return ObjectSP();
}
template <class IntType>
bool GetItemAtIndexAsInteger(size_t idx, IntType &result) const {
ObjectSP value_sp = GetItemAtIndex(idx);
if (value_sp.get()) {
if (auto int_value = value_sp->GetAsInteger()) {
result = static_cast<IntType>(int_value->GetValue());
return true;
}
}
return false;
}
template <class IntType>
bool GetItemAtIndexAsInteger(size_t idx, IntType &result,
IntType default_val) const {
bool success = GetItemAtIndexAsInteger(idx, result);
if (!success)
result = default_val;
return success;
}
bool GetItemAtIndexAsString(size_t idx, llvm::StringRef &result) const {
ObjectSP value_sp = GetItemAtIndex(idx);
if (value_sp.get()) {
if (auto string_value = value_sp->GetAsString()) {
result = string_value->GetValue();
return true;
}
}
return false;
}
bool GetItemAtIndexAsString(size_t idx, llvm::StringRef &result,
llvm::StringRef default_val) const {
bool success = GetItemAtIndexAsString(idx, result);
if (!success)
result = default_val;
return success;
}
bool GetItemAtIndexAsString(size_t idx, ConstString &result) const {
ObjectSP value_sp = GetItemAtIndex(idx);
if (value_sp.get()) {
if (auto string_value = value_sp->GetAsString()) {
result = ConstString(string_value->GetValue());
return true;
}
}
return false;
}
bool GetItemAtIndexAsString(size_t idx, ConstString &result,
const char *default_val) const {
bool success = GetItemAtIndexAsString(idx, result);
if (!success)
result.SetCString(default_val);
return success;
}
bool GetItemAtIndexAsDictionary(size_t idx, Dictionary *&result) const {
result = nullptr;
ObjectSP value_sp = GetItemAtIndex(idx);
if (value_sp.get()) {
result = value_sp->GetAsDictionary();
return (result != nullptr);
}
return false;
}
bool GetItemAtIndexAsArray(size_t idx, Array *&result) const {
result = nullptr;
ObjectSP value_sp = GetItemAtIndex(idx);
if (value_sp.get()) {
result = value_sp->GetAsArray();
return (result != nullptr);
}
return false;
}
void Push(const ObjectSP &item) { m_items.push_back(item); }
void AddItem(const ObjectSP &item) { m_items.push_back(item); }
void Serialize(llvm::json::OStream &s) const override;
protected:
typedef std::vector<ObjectSP> collection;
collection m_items;
};
class Integer : public Object {
public:
Integer(uint64_t i = 0)
: Object(lldb::eStructuredDataTypeInteger), m_value(i) {}
~Integer() override = default;
void SetValue(uint64_t value) { m_value = value; }
uint64_t GetValue() { return m_value; }
void Serialize(llvm::json::OStream &s) const override;
protected:
uint64_t m_value;
};
class Float : public Object {
public:
Float(double d = 0.0)
: Object(lldb::eStructuredDataTypeFloat), m_value(d) {}
~Float() override = default;
void SetValue(double value) { m_value = value; }
double GetValue() { return m_value; }
void Serialize(llvm::json::OStream &s) const override;
protected:
double m_value;
};
class Boolean : public Object {
public:
Boolean(bool b = false)
: Object(lldb::eStructuredDataTypeBoolean), m_value(b) {}
~Boolean() override = default;
void SetValue(bool value) { m_value = value; }
bool GetValue() { return m_value; }
void Serialize(llvm::json::OStream &s) const override;
protected:
bool m_value;
};
class String : public Object {
public:
String() : Object(lldb::eStructuredDataTypeString) {}
explicit String(llvm::StringRef S)
: Object(lldb::eStructuredDataTypeString), m_value(S) {}
void SetValue(llvm::StringRef S) { m_value = std::string(S); }
llvm::StringRef GetValue() { return m_value; }
void Serialize(llvm::json::OStream &s) const override;
protected:
std::string m_value;
};
class Dictionary : public Object {
public:
Dictionary() : Object(lldb::eStructuredDataTypeDictionary), m_dict() {}
Dictionary(ObjectSP obj_sp)
: Object(lldb::eStructuredDataTypeDictionary), m_dict() {
if (!obj_sp || obj_sp->GetType() != lldb::eStructuredDataTypeDictionary) {
SetType(lldb::eStructuredDataTypeInvalid);
return;
}
Dictionary *dict = obj_sp->GetAsDictionary();
m_dict = dict->m_dict;
}
~Dictionary() override = default;
size_t GetSize() const { return m_dict.size(); }
void ForEach(std::function<bool(ConstString key, Object *object)> const
&callback) const {
for (const auto &pair : m_dict) {
if (!callback(pair.first, pair.second.get()))
break;
}
}
ObjectSP GetKeys() const {
auto object_sp = std::make_shared<Array>();
collection::const_iterator iter;
for (iter = m_dict.begin(); iter != m_dict.end(); ++iter) {
auto key_object_sp = std::make_shared<String>();
key_object_sp->SetValue(iter->first.AsCString());
object_sp->Push(key_object_sp);
}
return object_sp;
}
ObjectSP GetValueForKey(llvm::StringRef key) const {
ObjectSP value_sp;
if (!key.empty()) {
ConstString key_cs(key);
collection::const_iterator iter = m_dict.find(key_cs);
if (iter != m_dict.end())
value_sp = iter->second;
}
return value_sp;
}
bool GetValueForKeyAsBoolean(llvm::StringRef key, bool &result) const {
bool success = false;
ObjectSP value_sp = GetValueForKey(key);
if (value_sp.get()) {
Boolean *result_ptr = value_sp->GetAsBoolean();
if (result_ptr) {
result = result_ptr->GetValue();
success = true;
}
}
return success;
}
template <class IntType>
bool GetValueForKeyAsInteger(llvm::StringRef key, IntType &result) const {
ObjectSP value_sp = GetValueForKey(key);
if (value_sp) {
if (auto int_value = value_sp->GetAsInteger()) {
result = static_cast<IntType>(int_value->GetValue());
return true;
}
}
return false;
}
template <class IntType>
bool GetValueForKeyAsInteger(llvm::StringRef key, IntType &result,
IntType default_val) const {
bool success = GetValueForKeyAsInteger<IntType>(key, result);
if (!success)
result = default_val;
return success;
}
bool GetValueForKeyAsString(llvm::StringRef key,
llvm::StringRef &result) const {
ObjectSP value_sp = GetValueForKey(key);
if (value_sp.get()) {
if (auto string_value = value_sp->GetAsString()) {
result = string_value->GetValue();
return true;
}
}
return false;
}
bool GetValueForKeyAsString(llvm::StringRef key, llvm::StringRef &result,
const char *default_val) const {
bool success = GetValueForKeyAsString(key, result);
if (!success) {
if (default_val)
result = default_val;
else
result = llvm::StringRef();
}
return success;
}
bool GetValueForKeyAsString(llvm::StringRef key,
ConstString &result) const {
ObjectSP value_sp = GetValueForKey(key);
if (value_sp.get()) {
if (auto string_value = value_sp->GetAsString()) {
result = ConstString(string_value->GetValue());
return true;
}
}
return false;
}
bool GetValueForKeyAsString(llvm::StringRef key, ConstString &result,
const char *default_val) const {
bool success = GetValueForKeyAsString(key, result);
if (!success)
result.SetCString(default_val);
return success;
}
bool GetValueForKeyAsDictionary(llvm::StringRef key,
Dictionary *&result) const {
result = nullptr;
ObjectSP value_sp = GetValueForKey(key);
if (value_sp.get()) {
result = value_sp->GetAsDictionary();
return (result != nullptr);
}
return false;
}
bool GetValueForKeyAsArray(llvm::StringRef key, Array *&result) const {
result = nullptr;
ObjectSP value_sp = GetValueForKey(key);
if (value_sp.get()) {
result = value_sp->GetAsArray();
return (result != nullptr);
}
return false;
}
bool HasKey(llvm::StringRef key) const {
ConstString key_cs(key);
collection::const_iterator search = m_dict.find(key_cs);
return search != m_dict.end();
}
void AddItem(llvm::StringRef key, ObjectSP value_sp) {
ConstString key_cs(key);
m_dict[key_cs] = std::move(value_sp);
}
void AddIntegerItem(llvm::StringRef key, uint64_t value) {
AddItem(key, std::make_shared<Integer>(value));
}
void AddFloatItem(llvm::StringRef key, double value) {
AddItem(key, std::make_shared<Float>(value));
}
void AddStringItem(llvm::StringRef key, llvm::StringRef value) {
AddItem(key, std::make_shared<String>(std::move(value)));
}
void AddBooleanItem(llvm::StringRef key, bool value) {
AddItem(key, std::make_shared<Boolean>(value));
}
void Serialize(llvm::json::OStream &s) const override;
protected:
typedef std::map<ConstString, ObjectSP> collection;
collection m_dict;
};
class Null : public Object {
public:
Null() : Object(lldb::eStructuredDataTypeNull) {}
~Null() override = default;
bool IsValid() const override { return false; }
void Serialize(llvm::json::OStream &s) const override;
};
class Generic : public Object {
public:
explicit Generic(void *object = nullptr)
: Object(lldb::eStructuredDataTypeGeneric), m_object(object) {}
void SetValue(void *value) { m_object = value; }
void *GetValue() const { return m_object; }
bool IsValid() const override { return m_object != nullptr; }
void Serialize(llvm::json::OStream &s) const override;
private:
void *m_object;
};
static ObjectSP ParseJSON(const std::string &json_text);
static ObjectSP ParseJSONFromFile(const FileSpec &file, Status &error);
};
} // namespace lldb_private
#endif // LLDB_UTILITY_STRUCTUREDDATA_H