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