//===-- StructuredData.h ----------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef liblldb_StructuredData_h_ #define liblldb_StructuredData_h_ // C Includes // C++ Includes #include #include #include #include #include #include // Other libraries and framework includes #include "llvm/ADT/StringRef.h" // Project includes #include "lldb/lldb-defines.h" #include "lldb/Core/ConstString.h" #include "lldb/Core/Stream.h" namespace lldb_private { //---------------------------------------------------------------------- /// @class StructuredData StructuredData.h "lldb/Core/StructuredData.h" /// @brief 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 ObjectSP; typedef std::shared_ptr ArraySP; typedef std::shared_ptr IntegerSP; typedef std::shared_ptr FloatSP; typedef std::shared_ptr BooleanSP; typedef std::shared_ptr StringSP; typedef std::shared_ptr DictionarySP; typedef std::shared_ptr GenericSP; enum class Type { eTypeInvalid = -1, eTypeNull = 0, eTypeGeneric, eTypeArray, eTypeInteger, eTypeFloat, eTypeBoolean, eTypeString, eTypeDictionary }; class Object : public std::enable_shared_from_this { public: Object (Type t = Type::eTypeInvalid) : m_type (t) { } virtual ~Object() = default; virtual bool IsValid() const { return true; } virtual void Clear () { m_type = Type::eTypeInvalid; } Type GetType () const { return m_type; } void SetType (Type t) { m_type = t; } Array * GetAsArray () { return ((m_type == Type::eTypeArray) ? static_cast(this) : nullptr); } Dictionary * GetAsDictionary () { return ((m_type == Type::eTypeDictionary) ? static_cast(this) : nullptr); } Integer * GetAsInteger () { return ((m_type == Type::eTypeInteger) ? static_cast(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 == Type::eTypeFloat) ? static_cast(this) : nullptr); } double GetFloatValue (double fail_value = 0.0) { Float *f = GetAsFloat (); return ((f != nullptr) ? f->GetValue() : fail_value); } Boolean * GetAsBoolean () { return ((m_type == Type::eTypeBoolean) ? static_cast(this) : nullptr); } bool GetBooleanValue (bool fail_value = false) { Boolean *b = GetAsBoolean (); return ((b != nullptr) ? b->GetValue() : fail_value); } String * GetAsString () { return ((m_type == Type::eTypeString) ? static_cast(this) : nullptr); } std::string GetStringValue(const char *fail_value = nullptr) { String *s = GetAsString (); if (s) return s->GetValue(); if (fail_value && fail_value[0]) return std::string(fail_value); return std::string(); } Generic * GetAsGeneric() { return ((m_type == Type::eTypeGeneric) ? static_cast(this) : nullptr); } ObjectSP GetObjectForDotSeparatedPath (llvm::StringRef path); void DumpToStdout() const; virtual void Dump (Stream &s) const = 0; private: Type m_type; }; class Array : public Object { public: Array () : Object (Type::eTypeArray) { } ~Array() override = default; bool ForEach (std::function const &foreach_callback) const { for (const auto &object_sp : m_items) { if (foreach_callback(object_sp.get()) == false) 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 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(int_value->GetValue()); return true; } } return false; } template 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, std::string &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, std::string &result, const std::string &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(ObjectSP item) { m_items.push_back(item); } void AddItem(ObjectSP item) { m_items.push_back(item); } void Dump(Stream &s) const override; protected: typedef std::vector collection; collection m_items; }; class Integer : public Object { public: Integer (uint64_t i = 0) : Object (Type::eTypeInteger), m_value (i) { } ~Integer() override = default; void SetValue (uint64_t value) { m_value = value; } uint64_t GetValue () { return m_value; } void Dump(Stream &s) const override; protected: uint64_t m_value; }; class Float : public Object { public: Float (double d = 0.0) : Object (Type::eTypeFloat), m_value (d) { } ~Float() override = default; void SetValue (double value) { m_value = value; } double GetValue () { return m_value; } void Dump(Stream &s) const override; protected: double m_value; }; class Boolean : public Object { public: Boolean (bool b = false) : Object (Type::eTypeBoolean), m_value (b) { } ~Boolean() override = default; void SetValue (bool value) { m_value = value; } bool GetValue () { return m_value; } void Dump(Stream &s) const override; protected: bool m_value; }; class String : public Object { public: String(const char *cstr = nullptr) : Object (Type::eTypeString), m_value () { if (cstr) m_value = cstr; } String (const std::string &s) : Object (Type::eTypeString), m_value (s) { } String (const std::string &&s) : Object (Type::eTypeString), m_value (s) { } void SetValue (const std::string &string) { m_value = string; } const std::string & GetValue () { return m_value; } void Dump(Stream &s) const override; protected: std::string m_value; }; class Dictionary : public Object { public: Dictionary () : Object (Type::eTypeDictionary), m_dict () { } ~Dictionary() override = default; size_t GetSize() const { return m_dict.size(); } void ForEach (std::function const &callback) const { for (const auto &pair : m_dict) { if (callback (pair.first, pair.second.get()) == false) break; } } ObjectSP GetKeys() const { ObjectSP object_sp(new Array ()); Array *array = object_sp->GetAsArray(); collection::const_iterator iter; for (iter = m_dict.begin(); iter != m_dict.end(); ++iter) { ObjectSP key_object_sp(new String()); key_object_sp->GetAsString()->SetValue(iter->first.AsCString()); array->Push(key_object_sp); } return object_sp; } ObjectSP GetValueForKey(llvm::StringRef key) const { ObjectSP value_sp; if (!key.empty()) { ConstString key_cs(key); for (collection::const_iterator iter = m_dict.begin(); iter != m_dict.end(); ++iter) { if (key_cs == iter->first) { value_sp = iter->second; break; } } } return value_sp; } template 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(int_value->GetValue()); return true; } } return false; } template bool GetValueForKeyAsInteger(llvm::StringRef key, IntType &result, IntType default_val) const { bool success = GetValueForKeyAsInteger(key, result); if (!success) result = default_val; return success; } bool GetValueForKeyAsString(llvm::StringRef key, std::string &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, std::string &result, const char *default_val) const { bool success = GetValueForKeyAsString(key, result); if (!success) { if (default_val) result = default_val; else result.clear(); } 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] = value_sp; } void AddIntegerItem (llvm::StringRef key, uint64_t value) { AddItem (key, ObjectSP (new Integer(value))); } void AddFloatItem (llvm::StringRef key, double value) { AddItem (key, ObjectSP (new Float(value))); } void AddStringItem (llvm::StringRef key, std::string value) { AddItem (key, ObjectSP (new String(std::move(value)))); } void AddBooleanItem (llvm::StringRef key, bool value) { AddItem (key, ObjectSP (new Boolean(value))); } void Dump(Stream &s) const override; protected: typedef std::map collection; collection m_dict; }; class Null : public Object { public: Null () : Object (Type::eTypeNull) { } ~Null() override = default; bool IsValid() const override { return false; } void Dump(Stream &s) const override; }; class Generic : public Object { public: explicit Generic(void *object = nullptr) : Object (Type::eTypeGeneric), 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 Dump(Stream &s) const override; private: void *m_object; }; static ObjectSP ParseJSON (std::string json_text); }; } // namespace lldb_private #endif // liblldb_StructuredData_h_