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