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) 73 : m_type(t) {} 74 75 virtual ~Object() = default; 76 77 virtual bool IsValid() const { return true; } 78 79 virtual void Clear() { m_type = lldb::eStructuredDataTypeInvalid; } 80 81 lldb::StructuredDataType GetType() const { return m_type; } 82 83 void SetType(lldb::StructuredDataType t) { m_type = t; } 84 85 Array *GetAsArray() { 86 return ((m_type == lldb::eStructuredDataTypeArray) 87 ? static_cast<Array *>(this) 88 : nullptr); 89 } 90 91 Dictionary *GetAsDictionary() { 92 return ((m_type == lldb::eStructuredDataTypeDictionary) 93 ? static_cast<Dictionary *>(this) 94 : nullptr); 95 } 96 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 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 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 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 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 161 private: 162 lldb::StructuredDataType m_type; 163 }; 164 165 class Array : public Object { 166 public: 167 Array() : Object(lldb::eStructuredDataTypeArray) {} 168 169 ~Array() override = default; 170 171 bool 172 ForEach(std::function<bool(Object *object)> const &foreach_callback) const { 173 for (const auto &object_sp : m_items) { 174 if (!foreach_callback(object_sp.get())) 175 return false; 176 } 177 return true; 178 } 179 180 size_t GetSize() const { return m_items.size(); } 181 182 ObjectSP operator[](size_t idx) { 183 if (idx < m_items.size()) 184 return m_items[idx]; 185 return ObjectSP(); 186 } 187 188 ObjectSP GetItemAtIndex(size_t idx) const { 189 assert(idx < GetSize()); 190 if (idx < m_items.size()) 191 return m_items[idx]; 192 return ObjectSP(); 193 } 194 195 template <class IntType> 196 bool GetItemAtIndexAsInteger(size_t idx, IntType &result) const { 197 ObjectSP value_sp = GetItemAtIndex(idx); 198 if (value_sp.get()) { 199 if (auto int_value = value_sp->GetAsInteger()) { 200 result = static_cast<IntType>(int_value->GetValue()); 201 return true; 202 } 203 } 204 return false; 205 } 206 207 template <class IntType> 208 bool GetItemAtIndexAsInteger(size_t idx, IntType &result, 209 IntType default_val) const { 210 bool success = GetItemAtIndexAsInteger(idx, result); 211 if (!success) 212 result = default_val; 213 return success; 214 } 215 216 bool GetItemAtIndexAsString(size_t idx, llvm::StringRef &result) const { 217 ObjectSP value_sp = GetItemAtIndex(idx); 218 if (value_sp.get()) { 219 if (auto string_value = value_sp->GetAsString()) { 220 result = string_value->GetValue(); 221 return true; 222 } 223 } 224 return false; 225 } 226 227 bool GetItemAtIndexAsString(size_t idx, llvm::StringRef &result, 228 llvm::StringRef default_val) const { 229 bool success = GetItemAtIndexAsString(idx, result); 230 if (!success) 231 result = default_val; 232 return success; 233 } 234 235 bool GetItemAtIndexAsString(size_t idx, ConstString &result) const { 236 ObjectSP value_sp = GetItemAtIndex(idx); 237 if (value_sp.get()) { 238 if (auto string_value = value_sp->GetAsString()) { 239 result = ConstString(string_value->GetValue()); 240 return true; 241 } 242 } 243 return false; 244 } 245 246 bool GetItemAtIndexAsString(size_t idx, ConstString &result, 247 const char *default_val) const { 248 bool success = GetItemAtIndexAsString(idx, result); 249 if (!success) 250 result.SetCString(default_val); 251 return success; 252 } 253 254 bool GetItemAtIndexAsDictionary(size_t idx, Dictionary *&result) const { 255 result = nullptr; 256 ObjectSP value_sp = GetItemAtIndex(idx); 257 if (value_sp.get()) { 258 result = value_sp->GetAsDictionary(); 259 return (result != nullptr); 260 } 261 return false; 262 } 263 264 bool GetItemAtIndexAsArray(size_t idx, Array *&result) const { 265 result = nullptr; 266 ObjectSP value_sp = GetItemAtIndex(idx); 267 if (value_sp.get()) { 268 result = value_sp->GetAsArray(); 269 return (result != nullptr); 270 } 271 return false; 272 } 273 274 void Push(const ObjectSP &item) { m_items.push_back(item); } 275 276 void AddItem(const ObjectSP &item) { m_items.push_back(item); } 277 278 void Serialize(llvm::json::OStream &s) const override; 279 280 protected: 281 typedef std::vector<ObjectSP> collection; 282 collection m_items; 283 }; 284 285 class Integer : public Object { 286 public: 287 Integer(uint64_t i = 0) 288 : Object(lldb::eStructuredDataTypeInteger), m_value(i) {} 289 290 ~Integer() override = default; 291 292 void SetValue(uint64_t value) { m_value = value; } 293 294 uint64_t GetValue() { return m_value; } 295 296 void Serialize(llvm::json::OStream &s) const override; 297 298 protected: 299 uint64_t m_value; 300 }; 301 302 class Float : public Object { 303 public: 304 Float(double d = 0.0) 305 : Object(lldb::eStructuredDataTypeFloat), m_value(d) {} 306 307 ~Float() override = default; 308 309 void SetValue(double value) { m_value = value; } 310 311 double GetValue() { return m_value; } 312 313 void Serialize(llvm::json::OStream &s) const override; 314 315 protected: 316 double m_value; 317 }; 318 319 class Boolean : public Object { 320 public: 321 Boolean(bool b = false) 322 : Object(lldb::eStructuredDataTypeBoolean), m_value(b) {} 323 324 ~Boolean() override = default; 325 326 void SetValue(bool value) { m_value = value; } 327 328 bool GetValue() { return m_value; } 329 330 void Serialize(llvm::json::OStream &s) const override; 331 332 protected: 333 bool m_value; 334 }; 335 336 class String : public Object { 337 public: 338 String() : Object(lldb::eStructuredDataTypeString) {} 339 explicit String(llvm::StringRef S) 340 : Object(lldb::eStructuredDataTypeString), m_value(S) {} 341 342 void SetValue(llvm::StringRef S) { m_value = std::string(S); } 343 344 llvm::StringRef GetValue() { return m_value; } 345 346 void Serialize(llvm::json::OStream &s) const override; 347 348 protected: 349 std::string m_value; 350 }; 351 352 class Dictionary : public Object { 353 public: 354 Dictionary() : Object(lldb::eStructuredDataTypeDictionary) {} 355 356 Dictionary(ObjectSP obj_sp) : Object(lldb::eStructuredDataTypeDictionary) { 357 if (!obj_sp || obj_sp->GetType() != lldb::eStructuredDataTypeDictionary) { 358 SetType(lldb::eStructuredDataTypeInvalid); 359 return; 360 } 361 362 Dictionary *dict = obj_sp->GetAsDictionary(); 363 m_dict = dict->m_dict; 364 } 365 366 ~Dictionary() override = default; 367 368 size_t GetSize() const { return m_dict.size(); } 369 370 void ForEach(std::function<bool(ConstString key, Object *object)> const 371 &callback) const { 372 for (const auto &pair : m_dict) { 373 if (!callback(pair.first, pair.second.get())) 374 break; 375 } 376 } 377 378 ArraySP GetKeys() const { 379 auto array_sp = std::make_shared<Array>(); 380 collection::const_iterator iter; 381 for (iter = m_dict.begin(); iter != m_dict.end(); ++iter) { 382 auto key_object_sp = std::make_shared<String>(); 383 key_object_sp->SetValue(iter->first.AsCString()); 384 array_sp->Push(key_object_sp); 385 } 386 return array_sp; 387 } 388 389 ObjectSP GetValueForKey(llvm::StringRef key) const { 390 ObjectSP value_sp; 391 if (!key.empty()) { 392 ConstString key_cs(key); 393 collection::const_iterator iter = m_dict.find(key_cs); 394 if (iter != m_dict.end()) 395 value_sp = iter->second; 396 } 397 return value_sp; 398 } 399 400 bool GetValueForKeyAsBoolean(llvm::StringRef key, bool &result) const { 401 bool success = false; 402 ObjectSP value_sp = GetValueForKey(key); 403 if (value_sp.get()) { 404 Boolean *result_ptr = value_sp->GetAsBoolean(); 405 if (result_ptr) { 406 result = result_ptr->GetValue(); 407 success = true; 408 } 409 } 410 return success; 411 } 412 template <class IntType> 413 bool GetValueForKeyAsInteger(llvm::StringRef key, IntType &result) const { 414 ObjectSP value_sp = GetValueForKey(key); 415 if (value_sp) { 416 if (auto int_value = value_sp->GetAsInteger()) { 417 result = static_cast<IntType>(int_value->GetValue()); 418 return true; 419 } 420 } 421 return false; 422 } 423 424 template <class IntType> 425 bool GetValueForKeyAsInteger(llvm::StringRef key, IntType &result, 426 IntType default_val) const { 427 bool success = GetValueForKeyAsInteger<IntType>(key, result); 428 if (!success) 429 result = default_val; 430 return success; 431 } 432 433 bool GetValueForKeyAsString(llvm::StringRef key, 434 llvm::StringRef &result) const { 435 ObjectSP value_sp = GetValueForKey(key); 436 if (value_sp.get()) { 437 if (auto string_value = value_sp->GetAsString()) { 438 result = string_value->GetValue(); 439 return true; 440 } 441 } 442 return false; 443 } 444 445 bool GetValueForKeyAsString(llvm::StringRef key, llvm::StringRef &result, 446 const char *default_val) const { 447 bool success = GetValueForKeyAsString(key, result); 448 if (!success) { 449 if (default_val) 450 result = default_val; 451 else 452 result = llvm::StringRef(); 453 } 454 return success; 455 } 456 457 bool GetValueForKeyAsString(llvm::StringRef key, 458 ConstString &result) const { 459 ObjectSP value_sp = GetValueForKey(key); 460 if (value_sp.get()) { 461 if (auto string_value = value_sp->GetAsString()) { 462 result = ConstString(string_value->GetValue()); 463 return true; 464 } 465 } 466 return false; 467 } 468 469 bool GetValueForKeyAsString(llvm::StringRef key, ConstString &result, 470 const char *default_val) const { 471 bool success = GetValueForKeyAsString(key, result); 472 if (!success) 473 result.SetCString(default_val); 474 return success; 475 } 476 477 bool GetValueForKeyAsDictionary(llvm::StringRef key, 478 Dictionary *&result) const { 479 result = nullptr; 480 ObjectSP value_sp = GetValueForKey(key); 481 if (value_sp.get()) { 482 result = value_sp->GetAsDictionary(); 483 return (result != nullptr); 484 } 485 return false; 486 } 487 488 bool GetValueForKeyAsArray(llvm::StringRef key, Array *&result) const { 489 result = nullptr; 490 ObjectSP value_sp = GetValueForKey(key); 491 if (value_sp.get()) { 492 result = value_sp->GetAsArray(); 493 return (result != nullptr); 494 } 495 return false; 496 } 497 498 bool HasKey(llvm::StringRef key) const { 499 ConstString key_cs(key); 500 collection::const_iterator search = m_dict.find(key_cs); 501 return search != m_dict.end(); 502 } 503 504 void AddItem(llvm::StringRef key, ObjectSP value_sp) { 505 ConstString key_cs(key); 506 m_dict[key_cs] = std::move(value_sp); 507 } 508 509 void AddIntegerItem(llvm::StringRef key, uint64_t value) { 510 AddItem(key, std::make_shared<Integer>(value)); 511 } 512 513 void AddFloatItem(llvm::StringRef key, double value) { 514 AddItem(key, std::make_shared<Float>(value)); 515 } 516 517 void AddStringItem(llvm::StringRef key, llvm::StringRef value) { 518 AddItem(key, std::make_shared<String>(std::move(value))); 519 } 520 521 void AddBooleanItem(llvm::StringRef key, bool value) { 522 AddItem(key, std::make_shared<Boolean>(value)); 523 } 524 525 void Serialize(llvm::json::OStream &s) const override; 526 527 protected: 528 typedef std::map<ConstString, ObjectSP> collection; 529 collection m_dict; 530 }; 531 532 class Null : public Object { 533 public: 534 Null() : Object(lldb::eStructuredDataTypeNull) {} 535 536 ~Null() override = default; 537 538 bool IsValid() const override { return false; } 539 540 void Serialize(llvm::json::OStream &s) const override; 541 }; 542 543 class Generic : public Object { 544 public: 545 explicit Generic(void *object = nullptr) 546 : Object(lldb::eStructuredDataTypeGeneric), m_object(object) {} 547 548 void SetValue(void *value) { m_object = value; } 549 550 void *GetValue() const { return m_object; } 551 552 bool IsValid() const override { return m_object != nullptr; } 553 554 void Serialize(llvm::json::OStream &s) const override; 555 556 private: 557 void *m_object; 558 }; 559 560 static ObjectSP ParseJSON(const std::string &json_text); 561 static ObjectSP ParseJSONFromFile(const FileSpec &file, Status &error); 562 }; 563 564 } // namespace lldb_private 565 566 #endif // LLDB_UTILITY_STRUCTUREDDATA_H 567