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 161 private: 162 lldb::StructuredDataType m_type; 163 }; 164 165 class Array : public Object { 166 public: Array()167 Array() : Object(lldb::eStructuredDataTypeArray) {} 168 169 ~Array() override = default; 170 171 bool ForEach(std::function<bool (Object * object)> const & foreach_callback)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 GetSize()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 GetItemAtIndex(size_t idx)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> GetItemAtIndexAsInteger(size_t idx,IntType & result)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> GetItemAtIndexAsInteger(size_t idx,IntType & result,IntType default_val)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 GetItemAtIndexAsString(size_t idx,llvm::StringRef & result)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 GetItemAtIndexAsString(size_t idx,llvm::StringRef & result,llvm::StringRef default_val)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 GetItemAtIndexAsString(size_t idx,ConstString & result)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 GetItemAtIndexAsString(size_t idx,ConstString & result,const char * default_val)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 GetItemAtIndexAsDictionary(size_t idx,Dictionary * & result)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 GetItemAtIndexAsArray(size_t idx,Array * & result)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 Push(const ObjectSP & item)274 void Push(const ObjectSP &item) { m_items.push_back(item); } 275 AddItem(const ObjectSP & item)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) Object(lldb::eStructuredDataTypeInteger)288 : Object(lldb::eStructuredDataTypeInteger), m_value(i) {} 289 290 ~Integer() override = default; 291 SetValue(uint64_t value)292 void SetValue(uint64_t value) { m_value = value; } 293 GetValue()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) Object(lldb::eStructuredDataTypeFloat)305 : Object(lldb::eStructuredDataTypeFloat), m_value(d) {} 306 307 ~Float() override = default; 308 SetValue(double value)309 void SetValue(double value) { m_value = value; } 310 GetValue()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) Object(lldb::eStructuredDataTypeBoolean)322 : Object(lldb::eStructuredDataTypeBoolean), m_value(b) {} 323 324 ~Boolean() override = default; 325 SetValue(bool value)326 void SetValue(bool value) { m_value = value; } 327 GetValue()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: String()338 String() : Object(lldb::eStructuredDataTypeString) {} String(llvm::StringRef S)339 explicit String(llvm::StringRef S) 340 : Object(lldb::eStructuredDataTypeString), m_value(S) {} 341 SetValue(llvm::StringRef S)342 void SetValue(llvm::StringRef S) { m_value = std::string(S); } 343 GetValue()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: Dictionary()354 Dictionary() : Object(lldb::eStructuredDataTypeDictionary), m_dict() {} 355 356 ~Dictionary() override = default; 357 GetSize()358 size_t GetSize() const { return m_dict.size(); } 359 ForEach(std::function<bool (ConstString key,Object * object)> const & callback)360 void ForEach(std::function<bool(ConstString key, Object *object)> const 361 &callback) const { 362 for (const auto &pair : m_dict) { 363 if (!callback(pair.first, pair.second.get())) 364 break; 365 } 366 } 367 GetKeys()368 ObjectSP GetKeys() const { 369 auto object_sp = std::make_shared<Array>(); 370 collection::const_iterator iter; 371 for (iter = m_dict.begin(); iter != m_dict.end(); ++iter) { 372 auto key_object_sp = std::make_shared<String>(); 373 key_object_sp->SetValue(iter->first.AsCString()); 374 object_sp->Push(key_object_sp); 375 } 376 return object_sp; 377 } 378 GetValueForKey(llvm::StringRef key)379 ObjectSP GetValueForKey(llvm::StringRef key) const { 380 ObjectSP value_sp; 381 if (!key.empty()) { 382 ConstString key_cs(key); 383 collection::const_iterator iter = m_dict.find(key_cs); 384 if (iter != m_dict.end()) 385 value_sp = iter->second; 386 } 387 return value_sp; 388 } 389 GetValueForKeyAsBoolean(llvm::StringRef key,bool & result)390 bool GetValueForKeyAsBoolean(llvm::StringRef key, bool &result) const { 391 bool success = false; 392 ObjectSP value_sp = GetValueForKey(key); 393 if (value_sp.get()) { 394 Boolean *result_ptr = value_sp->GetAsBoolean(); 395 if (result_ptr) { 396 result = result_ptr->GetValue(); 397 success = true; 398 } 399 } 400 return success; 401 } 402 template <class IntType> GetValueForKeyAsInteger(llvm::StringRef key,IntType & result)403 bool GetValueForKeyAsInteger(llvm::StringRef key, IntType &result) const { 404 ObjectSP value_sp = GetValueForKey(key); 405 if (value_sp) { 406 if (auto int_value = value_sp->GetAsInteger()) { 407 result = static_cast<IntType>(int_value->GetValue()); 408 return true; 409 } 410 } 411 return false; 412 } 413 414 template <class IntType> GetValueForKeyAsInteger(llvm::StringRef key,IntType & result,IntType default_val)415 bool GetValueForKeyAsInteger(llvm::StringRef key, IntType &result, 416 IntType default_val) const { 417 bool success = GetValueForKeyAsInteger<IntType>(key, result); 418 if (!success) 419 result = default_val; 420 return success; 421 } 422 GetValueForKeyAsString(llvm::StringRef key,llvm::StringRef & result)423 bool GetValueForKeyAsString(llvm::StringRef key, 424 llvm::StringRef &result) const { 425 ObjectSP value_sp = GetValueForKey(key); 426 if (value_sp.get()) { 427 if (auto string_value = value_sp->GetAsString()) { 428 result = string_value->GetValue(); 429 return true; 430 } 431 } 432 return false; 433 } 434 GetValueForKeyAsString(llvm::StringRef key,llvm::StringRef & result,const char * default_val)435 bool GetValueForKeyAsString(llvm::StringRef key, llvm::StringRef &result, 436 const char *default_val) const { 437 bool success = GetValueForKeyAsString(key, result); 438 if (!success) { 439 if (default_val) 440 result = default_val; 441 else 442 result = llvm::StringRef(); 443 } 444 return success; 445 } 446 GetValueForKeyAsString(llvm::StringRef key,ConstString & result)447 bool GetValueForKeyAsString(llvm::StringRef key, 448 ConstString &result) const { 449 ObjectSP value_sp = GetValueForKey(key); 450 if (value_sp.get()) { 451 if (auto string_value = value_sp->GetAsString()) { 452 result = ConstString(string_value->GetValue()); 453 return true; 454 } 455 } 456 return false; 457 } 458 GetValueForKeyAsString(llvm::StringRef key,ConstString & result,const char * default_val)459 bool GetValueForKeyAsString(llvm::StringRef key, ConstString &result, 460 const char *default_val) const { 461 bool success = GetValueForKeyAsString(key, result); 462 if (!success) 463 result.SetCString(default_val); 464 return success; 465 } 466 GetValueForKeyAsDictionary(llvm::StringRef key,Dictionary * & result)467 bool GetValueForKeyAsDictionary(llvm::StringRef key, 468 Dictionary *&result) const { 469 result = nullptr; 470 ObjectSP value_sp = GetValueForKey(key); 471 if (value_sp.get()) { 472 result = value_sp->GetAsDictionary(); 473 return (result != nullptr); 474 } 475 return false; 476 } 477 GetValueForKeyAsArray(llvm::StringRef key,Array * & result)478 bool GetValueForKeyAsArray(llvm::StringRef key, Array *&result) const { 479 result = nullptr; 480 ObjectSP value_sp = GetValueForKey(key); 481 if (value_sp.get()) { 482 result = value_sp->GetAsArray(); 483 return (result != nullptr); 484 } 485 return false; 486 } 487 HasKey(llvm::StringRef key)488 bool HasKey(llvm::StringRef key) const { 489 ConstString key_cs(key); 490 collection::const_iterator search = m_dict.find(key_cs); 491 return search != m_dict.end(); 492 } 493 AddItem(llvm::StringRef key,ObjectSP value_sp)494 void AddItem(llvm::StringRef key, ObjectSP value_sp) { 495 ConstString key_cs(key); 496 m_dict[key_cs] = std::move(value_sp); 497 } 498 AddIntegerItem(llvm::StringRef key,uint64_t value)499 void AddIntegerItem(llvm::StringRef key, uint64_t value) { 500 AddItem(key, std::make_shared<Integer>(value)); 501 } 502 AddFloatItem(llvm::StringRef key,double value)503 void AddFloatItem(llvm::StringRef key, double value) { 504 AddItem(key, std::make_shared<Float>(value)); 505 } 506 AddStringItem(llvm::StringRef key,llvm::StringRef value)507 void AddStringItem(llvm::StringRef key, llvm::StringRef value) { 508 AddItem(key, std::make_shared<String>(std::move(value))); 509 } 510 AddBooleanItem(llvm::StringRef key,bool value)511 void AddBooleanItem(llvm::StringRef key, bool value) { 512 AddItem(key, std::make_shared<Boolean>(value)); 513 } 514 515 void Serialize(llvm::json::OStream &s) const override; 516 517 protected: 518 typedef std::map<ConstString, ObjectSP> collection; 519 collection m_dict; 520 }; 521 522 class Null : public Object { 523 public: Null()524 Null() : Object(lldb::eStructuredDataTypeNull) {} 525 526 ~Null() override = default; 527 IsValid()528 bool IsValid() const override { return false; } 529 530 void Serialize(llvm::json::OStream &s) const override; 531 }; 532 533 class Generic : public Object { 534 public: 535 explicit Generic(void *object = nullptr) Object(lldb::eStructuredDataTypeGeneric)536 : Object(lldb::eStructuredDataTypeGeneric), m_object(object) {} 537 SetValue(void * value)538 void SetValue(void *value) { m_object = value; } 539 GetValue()540 void *GetValue() const { return m_object; } 541 IsValid()542 bool IsValid() const override { return m_object != nullptr; } 543 544 void Serialize(llvm::json::OStream &s) const override; 545 546 private: 547 void *m_object; 548 }; 549 550 static ObjectSP ParseJSON(const std::string &json_text); 551 static ObjectSP ParseJSONFromFile(const FileSpec &file, Status &error); 552 }; 553 554 } // namespace lldb_private 555 556 #endif // LLDB_UTILITY_STRUCTUREDDATA_H 557