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