• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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