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