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
31namespace lldb_private {
32class Status;
33}
34
35namespace 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
50class StructuredData {
51public:
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), m_dict() {}
355
356 ~Dictionary() override = default;
357
358 size_t GetSize() const { return m_dict.size(); }
359
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
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
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
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>
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>
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
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
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
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
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
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
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
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
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
499 void AddIntegerItem(llvm::StringRef key, uint64_t value) {
500 AddItem(key, std::make_shared<Integer>(value));
501 }
502
503 void AddFloatItem(llvm::StringRef key, double value) {
504 AddItem(key, std::make_shared<Float>(value));
505 }
506
507 void AddStringItem(llvm::StringRef key, llvm::StringRef value) {
508 AddItem(key, std::make_shared<String>(std::move(value)));
509 }
510
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:
524 Null() : Object(lldb::eStructuredDataTypeNull) {}
525
526 ~Null() override = default;
527
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)
536 : Object(lldb::eStructuredDataTypeGeneric), m_object(object) {}
537
538 void SetValue(void *value) { m_object = value; }
539
540 void *GetValue() const { return m_object; }
541
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