1 //===-- StructuredData.h ----------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLDB_UTILITY_STRUCTUREDDATA_H 10 #define LLDB_UTILITY_STRUCTUREDDATA_H 11 12 #include "llvm/ADT/StringRef.h" 13 #include "llvm/Support/JSON.h" 14 15 #include "lldb/Utility/ConstString.h" 16 #include "lldb/Utility/FileSpec.h" 17 #include "lldb/Utility/Stream.h" 18 #include "lldb/lldb-enumerations.h" 19 20 #include <cassert> 21 #include <cstddef> 22 #include <cstdint> 23 #include <functional> 24 #include <map> 25 #include <memory> 26 #include <string> 27 #include <type_traits> 28 #include <utility> 29 #include <vector> 30 31 namespace lldb_private { 32 class Status; 33 } 34 35 namespace lldb_private { 36 37 /// \class StructuredData StructuredData.h "lldb/Utility/StructuredData.h" 38 /// A class which can hold structured data 39 /// 40 /// The StructuredData class is designed to hold the data from a JSON or plist 41 /// style file -- a serialized data structure with dictionaries (maps, 42 /// hashes), arrays, and concrete values like integers, floating point 43 /// numbers, strings, booleans. 44 /// 45 /// StructuredData does not presuppose any knowledge of the schema for the 46 /// data it is holding; it can parse JSON data, for instance, and other parts 47 /// of lldb can iterate through the parsed data set to find keys and values 48 /// that may be present. 49 50 class StructuredData { 51 public: 52 class Object; 53 class Array; 54 class Integer; 55 class Float; 56 class Boolean; 57 class String; 58 class Dictionary; 59 class Generic; 60 61 typedef std::shared_ptr<Object> ObjectSP; 62 typedef std::shared_ptr<Array> ArraySP; 63 typedef std::shared_ptr<Integer> IntegerSP; 64 typedef std::shared_ptr<Float> FloatSP; 65 typedef std::shared_ptr<Boolean> BooleanSP; 66 typedef std::shared_ptr<String> StringSP; 67 typedef std::shared_ptr<Dictionary> DictionarySP; 68 typedef std::shared_ptr<Generic> GenericSP; 69 70 class Object : public std::enable_shared_from_this<Object> { 71 public: 72 Object(lldb::StructuredDataType t = lldb::eStructuredDataTypeInvalid) m_type(t)73 : m_type(t) {} 74 75 virtual ~Object() = default; 76 IsValid()77 virtual bool IsValid() const { return true; } 78 Clear()79 virtual void Clear() { m_type = lldb::eStructuredDataTypeInvalid; } 80 GetType()81 lldb::StructuredDataType GetType() const { return m_type; } 82 SetType(lldb::StructuredDataType t)83 void SetType(lldb::StructuredDataType t) { m_type = t; } 84 GetAsArray()85 Array *GetAsArray() { 86 return ((m_type == lldb::eStructuredDataTypeArray) 87 ? static_cast<Array *>(this) 88 : nullptr); 89 } 90 GetAsDictionary()91 Dictionary *GetAsDictionary() { 92 return ((m_type == lldb::eStructuredDataTypeDictionary) 93 ? static_cast<Dictionary *>(this) 94 : nullptr); 95 } 96 GetAsInteger()97 Integer *GetAsInteger() { 98 return ((m_type == lldb::eStructuredDataTypeInteger) 99 ? static_cast<Integer *>(this) 100 : nullptr); 101 } 102 103 uint64_t GetIntegerValue(uint64_t fail_value = 0) { 104 Integer *integer = GetAsInteger(); 105 return ((integer != nullptr) ? integer->GetValue() : fail_value); 106 } 107 GetAsFloat()108 Float *GetAsFloat() { 109 return ((m_type == lldb::eStructuredDataTypeFloat) 110 ? static_cast<Float *>(this) 111 : nullptr); 112 } 113 114 double GetFloatValue(double fail_value = 0.0) { 115 Float *f = GetAsFloat(); 116 return ((f != nullptr) ? f->GetValue() : fail_value); 117 } 118 GetAsBoolean()119 Boolean *GetAsBoolean() { 120 return ((m_type == lldb::eStructuredDataTypeBoolean) 121 ? static_cast<Boolean *>(this) 122 : nullptr); 123 } 124 125 bool GetBooleanValue(bool fail_value = false) { 126 Boolean *b = GetAsBoolean(); 127 return ((b != nullptr) ? b->GetValue() : fail_value); 128 } 129 GetAsString()130 String *GetAsString() { 131 return ((m_type == lldb::eStructuredDataTypeString) 132 ? static_cast<String *>(this) 133 : nullptr); 134 } 135 136 llvm::StringRef GetStringValue(const char *fail_value = nullptr) { 137 String *s = GetAsString(); 138 if (s) 139 return s->GetValue(); 140 141 return fail_value; 142 } 143 GetAsGeneric()144 Generic *GetAsGeneric() { 145 return ((m_type == lldb::eStructuredDataTypeGeneric) 146 ? static_cast<Generic *>(this) 147 : nullptr); 148 } 149 150 ObjectSP GetObjectForDotSeparatedPath(llvm::StringRef path); 151 152 void DumpToStdout(bool pretty_print = true) const; 153 154 virtual void Serialize(llvm::json::OStream &s) const = 0; 155 156 void Dump(lldb_private::Stream &s, bool pretty_print = true) const { 157 llvm::json::OStream jso(s.AsRawOstream(), pretty_print ? 2 : 0); 158 Serialize(jso); 159 } 160 GetDescription(lldb_private::Stream & s)161 virtual void GetDescription(lldb_private::Stream &s) const { 162 s.IndentMore(); 163 Dump(s, false); 164 s.IndentLess(); 165 } 166 167 private: 168 lldb::StructuredDataType m_type; 169 }; 170 171 class Array : public Object { 172 public: Array()173 Array() : Object(lldb::eStructuredDataTypeArray) {} 174 175 ~Array() override = default; 176 177 bool ForEach(std::function<bool (Object * object)> const & foreach_callback)178 ForEach(std::function<bool(Object *object)> const &foreach_callback) const { 179 for (const auto &object_sp : m_items) { 180 if (!foreach_callback(object_sp.get())) 181 return false; 182 } 183 return true; 184 } 185 GetSize()186 size_t GetSize() const { return m_items.size(); } 187 188 ObjectSP operator[](size_t idx) { 189 if (idx < m_items.size()) 190 return m_items[idx]; 191 return ObjectSP(); 192 } 193 GetItemAtIndex(size_t idx)194 ObjectSP GetItemAtIndex(size_t idx) const { 195 assert(idx < GetSize()); 196 if (idx < m_items.size()) 197 return m_items[idx]; 198 return ObjectSP(); 199 } 200 201 template <class IntType> GetItemAtIndexAsInteger(size_t idx,IntType & result)202 bool GetItemAtIndexAsInteger(size_t idx, IntType &result) const { 203 ObjectSP value_sp = GetItemAtIndex(idx); 204 if (value_sp.get()) { 205 if (auto int_value = value_sp->GetAsInteger()) { 206 result = static_cast<IntType>(int_value->GetValue()); 207 return true; 208 } 209 } 210 return false; 211 } 212 213 template <class IntType> GetItemAtIndexAsInteger(size_t idx,IntType & result,IntType default_val)214 bool GetItemAtIndexAsInteger(size_t idx, IntType &result, 215 IntType default_val) const { 216 bool success = GetItemAtIndexAsInteger(idx, result); 217 if (!success) 218 result = default_val; 219 return success; 220 } 221 GetItemAtIndexAsString(size_t idx,llvm::StringRef & result)222 bool GetItemAtIndexAsString(size_t idx, llvm::StringRef &result) const { 223 ObjectSP value_sp = GetItemAtIndex(idx); 224 if (value_sp.get()) { 225 if (auto string_value = value_sp->GetAsString()) { 226 result = string_value->GetValue(); 227 return true; 228 } 229 } 230 return false; 231 } 232 GetItemAtIndexAsString(size_t idx,llvm::StringRef & result,llvm::StringRef default_val)233 bool GetItemAtIndexAsString(size_t idx, llvm::StringRef &result, 234 llvm::StringRef default_val) const { 235 bool success = GetItemAtIndexAsString(idx, result); 236 if (!success) 237 result = default_val; 238 return success; 239 } 240 GetItemAtIndexAsString(size_t idx,ConstString & result)241 bool GetItemAtIndexAsString(size_t idx, ConstString &result) const { 242 ObjectSP value_sp = GetItemAtIndex(idx); 243 if (value_sp.get()) { 244 if (auto string_value = value_sp->GetAsString()) { 245 result = ConstString(string_value->GetValue()); 246 return true; 247 } 248 } 249 return false; 250 } 251 GetItemAtIndexAsString(size_t idx,ConstString & result,const char * default_val)252 bool GetItemAtIndexAsString(size_t idx, ConstString &result, 253 const char *default_val) const { 254 bool success = GetItemAtIndexAsString(idx, result); 255 if (!success) 256 result.SetCString(default_val); 257 return success; 258 } 259 GetItemAtIndexAsDictionary(size_t idx,Dictionary * & result)260 bool GetItemAtIndexAsDictionary(size_t idx, Dictionary *&result) const { 261 result = nullptr; 262 ObjectSP value_sp = GetItemAtIndex(idx); 263 if (value_sp.get()) { 264 result = value_sp->GetAsDictionary(); 265 return (result != nullptr); 266 } 267 return false; 268 } 269 GetItemAtIndexAsArray(size_t idx,Array * & result)270 bool GetItemAtIndexAsArray(size_t idx, Array *&result) const { 271 result = nullptr; 272 ObjectSP value_sp = GetItemAtIndex(idx); 273 if (value_sp.get()) { 274 result = value_sp->GetAsArray(); 275 return (result != nullptr); 276 } 277 return false; 278 } 279 Push(const ObjectSP & item)280 void Push(const ObjectSP &item) { m_items.push_back(item); } 281 AddItem(const ObjectSP & item)282 void AddItem(const ObjectSP &item) { m_items.push_back(item); } 283 284 void Serialize(llvm::json::OStream &s) const override; 285 286 void GetDescription(lldb_private::Stream &s) const override; 287 288 protected: 289 typedef std::vector<ObjectSP> collection; 290 collection m_items; 291 }; 292 293 class Integer : public Object { 294 public: 295 Integer(uint64_t i = 0) Object(lldb::eStructuredDataTypeInteger)296 : Object(lldb::eStructuredDataTypeInteger), m_value(i) {} 297 298 ~Integer() override = default; 299 SetValue(uint64_t value)300 void SetValue(uint64_t value) { m_value = value; } 301 GetValue()302 uint64_t GetValue() { return m_value; } 303 304 void Serialize(llvm::json::OStream &s) const override; 305 306 void GetDescription(lldb_private::Stream &s) const override; 307 308 protected: 309 uint64_t m_value; 310 }; 311 312 class Float : public Object { 313 public: 314 Float(double d = 0.0) Object(lldb::eStructuredDataTypeFloat)315 : Object(lldb::eStructuredDataTypeFloat), m_value(d) {} 316 317 ~Float() override = default; 318 SetValue(double value)319 void SetValue(double value) { m_value = value; } 320 GetValue()321 double GetValue() { return m_value; } 322 323 void Serialize(llvm::json::OStream &s) const override; 324 325 void GetDescription(lldb_private::Stream &s) const override; 326 327 protected: 328 double m_value; 329 }; 330 331 class Boolean : public Object { 332 public: 333 Boolean(bool b = false) Object(lldb::eStructuredDataTypeBoolean)334 : Object(lldb::eStructuredDataTypeBoolean), m_value(b) {} 335 336 ~Boolean() override = default; 337 SetValue(bool value)338 void SetValue(bool value) { m_value = value; } 339 GetValue()340 bool GetValue() { return m_value; } 341 342 void Serialize(llvm::json::OStream &s) const override; 343 344 void GetDescription(lldb_private::Stream &s) const override; 345 346 protected: 347 bool m_value; 348 }; 349 350 class String : public Object { 351 public: String()352 String() : Object(lldb::eStructuredDataTypeString) {} String(llvm::StringRef S)353 explicit String(llvm::StringRef S) 354 : Object(lldb::eStructuredDataTypeString), m_value(S) {} 355 SetValue(llvm::StringRef S)356 void SetValue(llvm::StringRef S) { m_value = std::string(S); } 357 GetValue()358 llvm::StringRef GetValue() { return m_value; } 359 360 void Serialize(llvm::json::OStream &s) const override; 361 362 void GetDescription(lldb_private::Stream &s) const override; 363 364 protected: 365 std::string m_value; 366 }; 367 368 class Dictionary : public Object { 369 public: Dictionary()370 Dictionary() : Object(lldb::eStructuredDataTypeDictionary) {} 371 Dictionary(ObjectSP obj_sp)372 Dictionary(ObjectSP obj_sp) : Object(lldb::eStructuredDataTypeDictionary) { 373 if (!obj_sp || obj_sp->GetType() != lldb::eStructuredDataTypeDictionary) { 374 SetType(lldb::eStructuredDataTypeInvalid); 375 return; 376 } 377 378 Dictionary *dict = obj_sp->GetAsDictionary(); 379 m_dict = dict->m_dict; 380 } 381 382 ~Dictionary() override = default; 383 GetSize()384 size_t GetSize() const { return m_dict.size(); } 385 ForEach(std::function<bool (ConstString key,Object * object)> const & callback)386 void ForEach(std::function<bool(ConstString key, Object *object)> const 387 &callback) const { 388 for (const auto &pair : m_dict) { 389 if (!callback(pair.first, pair.second.get())) 390 break; 391 } 392 } 393 GetKeys()394 ArraySP GetKeys() const { 395 auto array_sp = std::make_shared<Array>(); 396 collection::const_iterator iter; 397 for (iter = m_dict.begin(); iter != m_dict.end(); ++iter) { 398 auto key_object_sp = std::make_shared<String>(); 399 key_object_sp->SetValue(iter->first.AsCString()); 400 array_sp->Push(key_object_sp); 401 } 402 return array_sp; 403 } 404 GetValueForKey(llvm::StringRef key)405 ObjectSP GetValueForKey(llvm::StringRef key) const { 406 ObjectSP value_sp; 407 if (!key.empty()) { 408 ConstString key_cs(key); 409 collection::const_iterator iter = m_dict.find(key_cs); 410 if (iter != m_dict.end()) 411 value_sp = iter->second; 412 } 413 return value_sp; 414 } 415 GetValueForKeyAsBoolean(llvm::StringRef key,bool & result)416 bool GetValueForKeyAsBoolean(llvm::StringRef key, bool &result) const { 417 bool success = false; 418 ObjectSP value_sp = GetValueForKey(key); 419 if (value_sp.get()) { 420 Boolean *result_ptr = value_sp->GetAsBoolean(); 421 if (result_ptr) { 422 result = result_ptr->GetValue(); 423 success = true; 424 } 425 } 426 return success; 427 } 428 template <class IntType> GetValueForKeyAsInteger(llvm::StringRef key,IntType & result)429 bool GetValueForKeyAsInteger(llvm::StringRef key, IntType &result) const { 430 ObjectSP value_sp = GetValueForKey(key); 431 if (value_sp) { 432 if (auto int_value = value_sp->GetAsInteger()) { 433 result = static_cast<IntType>(int_value->GetValue()); 434 return true; 435 } 436 } 437 return false; 438 } 439 440 template <class IntType> GetValueForKeyAsInteger(llvm::StringRef key,IntType & result,IntType default_val)441 bool GetValueForKeyAsInteger(llvm::StringRef key, IntType &result, 442 IntType default_val) const { 443 bool success = GetValueForKeyAsInteger<IntType>(key, result); 444 if (!success) 445 result = default_val; 446 return success; 447 } 448 GetValueForKeyAsString(llvm::StringRef key,llvm::StringRef & result)449 bool GetValueForKeyAsString(llvm::StringRef key, 450 llvm::StringRef &result) const { 451 ObjectSP value_sp = GetValueForKey(key); 452 if (value_sp.get()) { 453 if (auto string_value = value_sp->GetAsString()) { 454 result = string_value->GetValue(); 455 return true; 456 } 457 } 458 return false; 459 } 460 GetValueForKeyAsString(llvm::StringRef key,llvm::StringRef & result,const char * default_val)461 bool GetValueForKeyAsString(llvm::StringRef key, llvm::StringRef &result, 462 const char *default_val) const { 463 bool success = GetValueForKeyAsString(key, result); 464 if (!success) { 465 if (default_val) 466 result = default_val; 467 else 468 result = llvm::StringRef(); 469 } 470 return success; 471 } 472 GetValueForKeyAsString(llvm::StringRef key,ConstString & result)473 bool GetValueForKeyAsString(llvm::StringRef key, 474 ConstString &result) const { 475 ObjectSP value_sp = GetValueForKey(key); 476 if (value_sp.get()) { 477 if (auto string_value = value_sp->GetAsString()) { 478 result = ConstString(string_value->GetValue()); 479 return true; 480 } 481 } 482 return false; 483 } 484 GetValueForKeyAsString(llvm::StringRef key,ConstString & result,const char * default_val)485 bool GetValueForKeyAsString(llvm::StringRef key, ConstString &result, 486 const char *default_val) const { 487 bool success = GetValueForKeyAsString(key, result); 488 if (!success) 489 result.SetCString(default_val); 490 return success; 491 } 492 GetValueForKeyAsDictionary(llvm::StringRef key,Dictionary * & result)493 bool GetValueForKeyAsDictionary(llvm::StringRef key, 494 Dictionary *&result) const { 495 result = nullptr; 496 ObjectSP value_sp = GetValueForKey(key); 497 if (value_sp.get()) { 498 result = value_sp->GetAsDictionary(); 499 return (result != nullptr); 500 } 501 return false; 502 } 503 GetValueForKeyAsArray(llvm::StringRef key,Array * & result)504 bool GetValueForKeyAsArray(llvm::StringRef key, Array *&result) const { 505 result = nullptr; 506 ObjectSP value_sp = GetValueForKey(key); 507 if (value_sp.get()) { 508 result = value_sp->GetAsArray(); 509 return (result != nullptr); 510 } 511 return false; 512 } 513 HasKey(llvm::StringRef key)514 bool HasKey(llvm::StringRef key) const { 515 ConstString key_cs(key); 516 collection::const_iterator search = m_dict.find(key_cs); 517 return search != m_dict.end(); 518 } 519 AddItem(llvm::StringRef key,ObjectSP value_sp)520 void AddItem(llvm::StringRef key, ObjectSP value_sp) { 521 ConstString key_cs(key); 522 m_dict[key_cs] = std::move(value_sp); 523 } 524 AddIntegerItem(llvm::StringRef key,uint64_t value)525 void AddIntegerItem(llvm::StringRef key, uint64_t value) { 526 AddItem(key, std::make_shared<Integer>(value)); 527 } 528 AddFloatItem(llvm::StringRef key,double value)529 void AddFloatItem(llvm::StringRef key, double value) { 530 AddItem(key, std::make_shared<Float>(value)); 531 } 532 AddStringItem(llvm::StringRef key,llvm::StringRef value)533 void AddStringItem(llvm::StringRef key, llvm::StringRef value) { 534 AddItem(key, std::make_shared<String>(std::move(value))); 535 } 536 AddBooleanItem(llvm::StringRef key,bool value)537 void AddBooleanItem(llvm::StringRef key, bool value) { 538 AddItem(key, std::make_shared<Boolean>(value)); 539 } 540 541 void Serialize(llvm::json::OStream &s) const override; 542 543 void GetDescription(lldb_private::Stream &s) const override; 544 545 protected: 546 typedef std::map<ConstString, ObjectSP> collection; 547 collection m_dict; 548 }; 549 550 class Null : public Object { 551 public: Null()552 Null() : Object(lldb::eStructuredDataTypeNull) {} 553 554 ~Null() override = default; 555 IsValid()556 bool IsValid() const override { return false; } 557 558 void Serialize(llvm::json::OStream &s) const override; 559 560 void GetDescription(lldb_private::Stream &s) const override; 561 }; 562 563 class Generic : public Object { 564 public: 565 explicit Generic(void *object = nullptr) Object(lldb::eStructuredDataTypeGeneric)566 : Object(lldb::eStructuredDataTypeGeneric), m_object(object) {} 567 SetValue(void * value)568 void SetValue(void *value) { m_object = value; } 569 GetValue()570 void *GetValue() const { return m_object; } 571 IsValid()572 bool IsValid() const override { return m_object != nullptr; } 573 574 void Serialize(llvm::json::OStream &s) const override; 575 576 void GetDescription(lldb_private::Stream &s) const override; 577 578 private: 579 void *m_object; 580 }; 581 582 static ObjectSP ParseJSON(const std::string &json_text); 583 static ObjectSP ParseJSONFromFile(const FileSpec &file, Status &error); 584 static bool IsRecordType(const ObjectSP object_sp); 585 }; 586 587 } // namespace lldb_private 588 589 #endif // LLDB_UTILITY_STRUCTUREDDATA_H 590