LLDB mainline
StructuredData.h
Go to the documentation of this file.
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/StringMap.h"
13#include "llvm/ADT/StringRef.h"
14#include "llvm/Support/JSON.h"
15
17#include "lldb/Utility/Stream.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 <variant>
30#include <vector>
31
32namespace lldb_private {
33class Status;
34}
35
36namespace lldb_private {
37
38/// \class StructuredData StructuredData.h "lldb/Utility/StructuredData.h"
39/// A class which can hold structured data
40///
41/// The StructuredData class is designed to hold the data from a JSON or plist
42/// style file -- a serialized data structure with dictionaries (maps,
43/// hashes), arrays, and concrete values like integers, floating point
44/// numbers, strings, booleans.
45///
46/// StructuredData does not presuppose any knowledge of the schema for the
47/// data it is holding; it can parse JSON data, for instance, and other parts
48/// of lldb can iterate through the parsed data set to find keys and values
49/// that may be present.
50
52 template <typename N> class Integer;
53
54public:
55 class Object;
56 class Array;
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<UnsignedInteger> UnsignedIntegerSP;
68 typedef std::shared_ptr<SignedInteger> SignedIntegerSP;
69 typedef std::shared_ptr<Float> FloatSP;
70 typedef std::shared_ptr<Boolean> BooleanSP;
71 typedef std::shared_ptr<String> StringSP;
72 typedef std::shared_ptr<Dictionary> DictionarySP;
73 typedef std::shared_ptr<Generic> GenericSP;
74
75 typedef std::variant<UnsignedIntegerSP, SignedIntegerSP> IntegerSP;
76
77 class Object : public std::enable_shared_from_this<Object> {
78 public:
80 : m_type(t) {}
81
82 virtual ~Object() = default;
83
84 virtual bool IsValid() const { return true; }
85
87
89
91
94 ? static_cast<Array *>(this)
95 : nullptr);
96 }
97
100 ? static_cast<Dictionary *>(this)
101 : nullptr);
102 }
103
105 // NOTE: For backward compatibility, eStructuredDataTypeInteger is
106 // the same as eStructuredDataTypeUnsignedInteger.
109 ? static_cast<UnsignedInteger *>(this)
110 : nullptr);
111 }
112
115 ? static_cast<SignedInteger *>(this)
116 : nullptr);
117 }
118
119 uint64_t GetUnsignedIntegerValue(uint64_t fail_value = 0) {
121 return ((integer != nullptr) ? integer->GetValue() : fail_value);
122 }
123
124 int64_t GetSignedIntegerValue(int64_t fail_value = 0) {
126 return ((integer != nullptr) ? integer->GetValue() : fail_value);
127 }
128
131 ? static_cast<Float *>(this)
132 : nullptr);
133 }
134
135 double GetFloatValue(double fail_value = 0.0) {
136 Float *f = GetAsFloat();
137 return ((f != nullptr) ? f->GetValue() : fail_value);
138 }
139
142 ? static_cast<Boolean *>(this)
143 : nullptr);
144 }
145
146 bool GetBooleanValue(bool fail_value = false) {
147 Boolean *b = GetAsBoolean();
148 return ((b != nullptr) ? b->GetValue() : fail_value);
149 }
150
153 ? static_cast<String *>(this)
154 : nullptr);
155 }
156
157 llvm::StringRef GetStringValue(const char *fail_value = nullptr) {
158 String *s = GetAsString();
159 if (s)
160 return s->GetValue();
161
162 return fail_value;
163 }
164
167 ? static_cast<Generic *>(this)
168 : nullptr);
169 }
170
171 ObjectSP GetObjectForDotSeparatedPath(llvm::StringRef path);
172
173 void DumpToStdout(bool pretty_print = true) const;
174
175 virtual void Serialize(llvm::json::OStream &s) const = 0;
176
177 void Dump(lldb_private::Stream &s, bool pretty_print = true) const {
178 llvm::json::OStream jso(s.AsRawOstream(), pretty_print ? 2 : 0);
179 Serialize(jso);
180 }
181
182 virtual void GetDescription(lldb_private::Stream &s) const {
183 s.IndentMore();
184 Dump(s, false);
185 s.IndentLess();
186 }
187
188 private:
190 };
191
192 class Array : public Object {
193 public:
194 Array() : Object(lldb::eStructuredDataTypeArray) {}
195
196 ~Array() override = default;
197
198 bool
199 ForEach(std::function<bool(Object *object)> const &foreach_callback) const {
200 for (const auto &object_sp : m_items) {
201 if (!foreach_callback(object_sp.get()))
202 return false;
203 }
204 return true;
205 }
206
207 size_t GetSize() const { return m_items.size(); }
208
209 ObjectSP operator[](size_t idx) {
210 if (idx < m_items.size())
211 return m_items[idx];
212 return ObjectSP();
213 }
214
215 ObjectSP GetItemAtIndex(size_t idx) const {
216 assert(idx < GetSize());
217 if (idx < m_items.size())
218 return m_items[idx];
219 return ObjectSP();
220 }
221
222 template <class IntType>
223 bool GetItemAtIndexAsInteger(size_t idx, IntType &result) const {
224 ObjectSP value_sp = GetItemAtIndex(idx);
225 if (value_sp.get()) {
226 if constexpr (std::numeric_limits<IntType>::is_signed) {
227 if (auto signed_value = value_sp->GetAsSignedInteger()) {
228 result = static_cast<IntType>(signed_value->GetValue());
229 return true;
230 }
231 } else {
232 if (auto unsigned_value = value_sp->GetAsUnsignedInteger()) {
233 result = static_cast<IntType>(unsigned_value->GetValue());
234 return true;
235 }
236 }
237 }
238 return false;
239 }
240
241 template <class IntType>
242 bool GetItemAtIndexAsInteger(size_t idx, IntType &result,
243 IntType default_val) const {
244 bool success = GetItemAtIndexAsInteger(idx, result);
245 if (!success)
246 result = default_val;
247 return success;
248 }
249
250 bool GetItemAtIndexAsString(size_t idx, llvm::StringRef &result) const {
251 ObjectSP value_sp = GetItemAtIndex(idx);
252 if (value_sp.get()) {
253 if (auto string_value = value_sp->GetAsString()) {
254 result = string_value->GetValue();
255 return true;
256 }
257 }
258 return false;
259 }
260
261 bool GetItemAtIndexAsString(size_t idx, llvm::StringRef &result,
262 llvm::StringRef default_val) const {
263 bool success = GetItemAtIndexAsString(idx, result);
264 if (!success)
265 result = default_val;
266 return success;
267 }
268
269 bool GetItemAtIndexAsDictionary(size_t idx, Dictionary *&result) const {
270 result = nullptr;
271 ObjectSP value_sp = GetItemAtIndex(idx);
272 if (value_sp.get()) {
273 result = value_sp->GetAsDictionary();
274 return (result != nullptr);
275 }
276 return false;
277 }
278
279 bool GetItemAtIndexAsArray(size_t idx, Array *&result) const {
280 result = nullptr;
281 ObjectSP value_sp = GetItemAtIndex(idx);
282 if (value_sp.get()) {
283 result = value_sp->GetAsArray();
284 return (result != nullptr);
285 }
286 return false;
287 }
288
289 void Push(const ObjectSP &item) { m_items.push_back(item); }
290
291 void AddItem(const ObjectSP &item) { m_items.push_back(item); }
292
293 template <typename T> void AddIntegerItem(T value) {
294 static_assert(std::is_integral<T>::value ||
295 std::is_floating_point<T>::value,
296 "value type should be integral");
297 if constexpr (std::numeric_limits<T>::is_signed)
298 AddItem(std::make_shared<SignedInteger>(value));
299 else
300 AddItem(std::make_shared<UnsignedInteger>(value));
301 }
302
303 void AddFloatItem(double value) { AddItem(std::make_shared<Float>(value)); }
304
305 void AddStringItem(llvm::StringRef value) {
306 AddItem(std::make_shared<String>(std::move(value)));
307 }
308
309 void AddBooleanItem(bool value) {
310 AddItem(std::make_shared<Boolean>(value));
311 }
312
313 void Serialize(llvm::json::OStream &s) const override;
314
315 void GetDescription(lldb_private::Stream &s) const override;
316
317 protected:
318 typedef std::vector<ObjectSP> collection;
320 };
321
322private:
323 template <typename N> class Integer : public Object {
324 static_assert(std::is_integral<N>::value, "N must be an integral type");
325
326 public:
327 Integer(N i = 0)
328 : Object(std::numeric_limits<N>::is_signed
329 ? lldb::eStructuredDataTypeSignedInteger
330 : lldb::eStructuredDataTypeUnsignedInteger),
331 m_value(i) {}
332 ~Integer() override = default;
333
334 void SetValue(N value) { m_value = value; }
335
336 N GetValue() { return m_value; }
337
338 void Serialize(llvm::json::OStream &s) const override {
339 s.value(static_cast<N>(m_value));
340 }
341
342 void GetDescription(lldb_private::Stream &s) const override {
343 s.Printf(std::numeric_limits<N>::is_signed ? "%" PRId64 : "%" PRIu64,
344 static_cast<N>(m_value));
345 }
346
347 protected:
349 };
350
351public:
352 class Float : public Object {
353 public:
354 Float(double d = 0.0)
355 : Object(lldb::eStructuredDataTypeFloat), m_value(d) {}
356
357 ~Float() override = default;
358
359 void SetValue(double value) { m_value = value; }
360
361 double GetValue() { return m_value; }
362
363 void Serialize(llvm::json::OStream &s) const override;
364
365 void GetDescription(lldb_private::Stream &s) const override;
366
367 protected:
368 double m_value;
369 };
370
371 class Boolean : public Object {
372 public:
373 Boolean(bool b = false)
374 : Object(lldb::eStructuredDataTypeBoolean), m_value(b) {}
375
376 ~Boolean() override = default;
377
378 void SetValue(bool value) { m_value = value; }
379
380 bool GetValue() { return m_value; }
381
382 void Serialize(llvm::json::OStream &s) const override;
383
384 void GetDescription(lldb_private::Stream &s) const override;
385
386 protected:
388 };
389
390 class String : public Object {
391 public:
392 String() : Object(lldb::eStructuredDataTypeString) {}
393 explicit String(llvm::StringRef S)
394 : Object(lldb::eStructuredDataTypeString), m_value(S) {}
395
396 void SetValue(llvm::StringRef S) { m_value = std::string(S); }
397
398 llvm::StringRef GetValue() { return m_value; }
399
400 void Serialize(llvm::json::OStream &s) const override;
401
402 void GetDescription(lldb_private::Stream &s) const override;
403
404 protected:
405 std::string m_value;
406 };
407
408 class Dictionary : public Object {
409 public:
410 Dictionary() : Object(lldb::eStructuredDataTypeDictionary) {}
411
412 Dictionary(ObjectSP obj_sp) : Object(lldb::eStructuredDataTypeDictionary) {
413 if (!obj_sp || obj_sp->GetType() != lldb::eStructuredDataTypeDictionary) {
415 return;
416 }
417
418 Dictionary *dict = obj_sp->GetAsDictionary();
419 m_dict = dict->m_dict;
420 }
421
422 ~Dictionary() override = default;
423
424 size_t GetSize() const { return m_dict.size(); }
425
426 void ForEach(std::function<bool(llvm::StringRef key, Object *object)> const
427 &callback) const {
428 for (const auto &pair : m_dict) {
429 if (!callback(pair.first(), pair.second.get()))
430 break;
431 }
432 }
433
434 ArraySP GetKeys() const {
435 auto array_sp = std::make_shared<Array>();
436 for (auto iter = m_dict.begin(); iter != m_dict.end(); ++iter) {
437 auto key_object_sp = std::make_shared<String>(iter->first());
438 array_sp->Push(key_object_sp);
439 }
440 return array_sp;
441 }
442
443 ObjectSP GetValueForKey(llvm::StringRef key) const {
444 return m_dict.lookup(key);
445 }
446
447 bool GetValueForKeyAsBoolean(llvm::StringRef key, bool &result) const {
448 bool success = false;
449 ObjectSP value_sp = GetValueForKey(key);
450 if (value_sp.get()) {
451 Boolean *result_ptr = value_sp->GetAsBoolean();
452 if (result_ptr) {
453 result = result_ptr->GetValue();
454 success = true;
455 }
456 }
457 return success;
458 }
459
460 template <class IntType>
461 bool GetValueForKeyAsInteger(llvm::StringRef key, IntType &result) const {
462 ObjectSP value_sp = GetValueForKey(key);
463 if (value_sp) {
464 if constexpr (std::numeric_limits<IntType>::is_signed) {
465 if (auto signed_value = value_sp->GetAsSignedInteger()) {
466 result = static_cast<IntType>(signed_value->GetValue());
467 return true;
468 }
469 } else {
470 if (auto unsigned_value = value_sp->GetAsUnsignedInteger()) {
471 result = static_cast<IntType>(unsigned_value->GetValue());
472 return true;
473 }
474 }
475 }
476 return false;
477 }
478
479 template <class IntType>
480 bool GetValueForKeyAsInteger(llvm::StringRef key, IntType &result,
481 IntType default_val) const {
482 bool success = GetValueForKeyAsInteger<IntType>(key, result);
483 if (!success)
484 result = default_val;
485 return success;
486 }
487
488 bool GetValueForKeyAsString(llvm::StringRef key,
489 llvm::StringRef &result) const {
490 ObjectSP value_sp = GetValueForKey(key);
491 if (value_sp.get()) {
492 if (auto string_value = value_sp->GetAsString()) {
493 result = string_value->GetValue();
494 return true;
495 }
496 }
497 return false;
498 }
499
500 bool GetValueForKeyAsString(llvm::StringRef key, llvm::StringRef &result,
501 const char *default_val) const {
502 bool success = GetValueForKeyAsString(key, result);
503 if (!success) {
504 if (default_val)
505 result = default_val;
506 else
507 result = llvm::StringRef();
508 }
509 return success;
510 }
511
512 bool GetValueForKeyAsDictionary(llvm::StringRef key,
513 Dictionary *&result) const {
514 result = nullptr;
515 ObjectSP value_sp = GetValueForKey(key);
516 if (value_sp.get()) {
517 result = value_sp->GetAsDictionary();
518 return (result != nullptr);
519 }
520 return false;
521 }
522
523 bool GetValueForKeyAsArray(llvm::StringRef key, Array *&result) const {
524 result = nullptr;
525 ObjectSP value_sp = GetValueForKey(key);
526 if (value_sp.get()) {
527 result = value_sp->GetAsArray();
528 return (result != nullptr);
529 }
530 return false;
531 }
532
533 bool HasKey(llvm::StringRef key) const { return m_dict.contains(key); }
534
535 void AddItem(llvm::StringRef key, ObjectSP value_sp) {
536 m_dict.insert_or_assign(key, std::move(value_sp));
537 }
538
539 template <typename T> void AddIntegerItem(llvm::StringRef key, T value) {
540 static_assert(std::is_integral<T>::value ||
541 std::is_floating_point<T>::value,
542 "value type should be integral");
543 if constexpr (std::numeric_limits<T>::is_signed)
544 AddItem(key, std::make_shared<SignedInteger>(value));
545 else
546 AddItem(key, std::make_shared<UnsignedInteger>(value));
547 }
548
549 void AddFloatItem(llvm::StringRef key, double value) {
550 AddItem(key, std::make_shared<Float>(value));
551 }
552
553 void AddStringItem(llvm::StringRef key, llvm::StringRef value) {
554 AddItem(key, std::make_shared<String>(std::move(value)));
555 }
556
557 void AddBooleanItem(llvm::StringRef key, bool value) {
558 AddItem(key, std::make_shared<Boolean>(value));
559 }
560
561 void Serialize(llvm::json::OStream &s) const override;
562
563 void GetDescription(lldb_private::Stream &s) const override;
564
565 protected:
566 llvm::StringMap<ObjectSP> m_dict;
567 };
568
569 class Null : public Object {
570 public:
571 Null() : Object(lldb::eStructuredDataTypeNull) {}
572
573 ~Null() override = default;
574
575 bool IsValid() const override { return false; }
576
577 void Serialize(llvm::json::OStream &s) const override;
578
579 void GetDescription(lldb_private::Stream &s) const override;
580 };
581
582 class Generic : public Object {
583 public:
584 explicit Generic(void *object = nullptr)
585 : Object(lldb::eStructuredDataTypeGeneric), m_object(object) {}
586
587 void SetValue(void *value) { m_object = value; }
588
589 void *GetValue() const { return m_object; }
590
591 bool IsValid() const override { return m_object != nullptr; }
592
593 void Serialize(llvm::json::OStream &s) const override;
594
595 void GetDescription(lldb_private::Stream &s) const override;
596
597 private:
598 void *m_object;
599 };
600
601 static ObjectSP ParseJSON(llvm::StringRef json_text);
602 static ObjectSP ParseJSONFromFile(const FileSpec &file, Status &error);
603 static bool IsRecordType(const ObjectSP object_sp);
604};
605
606} // namespace lldb_private
607
608#endif // LLDB_UTILITY_STRUCTUREDDATA_H
static llvm::raw_ostream & error(Stream &strm)
#define integer
A file utility class.
Definition: FileSpec.h:56
An error handling class.
Definition: Status.h:44
A stream class that can stream formatted output to a file.
Definition: Stream.h:28
llvm::raw_ostream & AsRawOstream()
Returns a raw_ostream that forwards the data to this Stream object.
Definition: Stream.h:357
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:107
void IndentLess(unsigned amount=2)
Decrement the current indentation level.
Definition: Stream.cpp:171
void IndentMore(unsigned amount=2)
Increment the current indentation level.
Definition: Stream.cpp:168
void AddItem(const ObjectSP &item)
void Serialize(llvm::json::OStream &s) const override
ObjectSP GetItemAtIndex(size_t idx) const
void AddStringItem(llvm::StringRef value)
bool GetItemAtIndexAsString(size_t idx, llvm::StringRef &result) const
std::vector< ObjectSP > collection
void GetDescription(lldb_private::Stream &s) const override
bool ForEach(std::function< bool(Object *object)> const &foreach_callback) const
void Push(const ObjectSP &item)
bool GetItemAtIndexAsString(size_t idx, llvm::StringRef &result, llvm::StringRef default_val) const
bool GetItemAtIndexAsArray(size_t idx, Array *&result) const
bool GetItemAtIndexAsDictionary(size_t idx, Dictionary *&result) const
bool GetItemAtIndexAsInteger(size_t idx, IntType &result, IntType default_val) const
bool GetItemAtIndexAsInteger(size_t idx, IntType &result) const
void Serialize(llvm::json::OStream &s) const override
void GetDescription(lldb_private::Stream &s) const override
void AddBooleanItem(llvm::StringRef key, bool value)
void Serialize(llvm::json::OStream &s) const override
bool GetValueForKeyAsInteger(llvm::StringRef key, IntType &result) const
bool GetValueForKeyAsString(llvm::StringRef key, llvm::StringRef &result) const
bool GetValueForKeyAsBoolean(llvm::StringRef key, bool &result) const
void AddFloatItem(llvm::StringRef key, double value)
bool GetValueForKeyAsInteger(llvm::StringRef key, IntType &result, IntType default_val) const
llvm::StringMap< ObjectSP > m_dict
void AddIntegerItem(llvm::StringRef key, T value)
ObjectSP GetValueForKey(llvm::StringRef key) const
void AddStringItem(llvm::StringRef key, llvm::StringRef value)
void GetDescription(lldb_private::Stream &s) const override
bool HasKey(llvm::StringRef key) const
void AddItem(llvm::StringRef key, ObjectSP value_sp)
bool GetValueForKeyAsArray(llvm::StringRef key, Array *&result) const
void ForEach(std::function< bool(llvm::StringRef key, Object *object)> const &callback) const
bool GetValueForKeyAsString(llvm::StringRef key, llvm::StringRef &result, const char *default_val) const
bool GetValueForKeyAsDictionary(llvm::StringRef key, Dictionary *&result) const
void Serialize(llvm::json::OStream &s) const override
void GetDescription(lldb_private::Stream &s) const override
void GetDescription(lldb_private::Stream &s) const override
void Serialize(llvm::json::OStream &s) const override
void GetDescription(lldb_private::Stream &s) const override
void Serialize(llvm::json::OStream &s) const override
void GetDescription(lldb_private::Stream &s) const override
void Serialize(llvm::json::OStream &s) const override
lldb::StructuredDataType m_type
virtual void Serialize(llvm::json::OStream &s) const =0
llvm::StringRef GetStringValue(const char *fail_value=nullptr)
void DumpToStdout(bool pretty_print=true) const
virtual void GetDescription(lldb_private::Stream &s) const
double GetFloatValue(double fail_value=0.0)
UnsignedInteger * GetAsUnsignedInteger()
Object(lldb::StructuredDataType t=lldb::eStructuredDataTypeInvalid)
int64_t GetSignedIntegerValue(int64_t fail_value=0)
bool GetBooleanValue(bool fail_value=false)
void SetType(lldb::StructuredDataType t)
void Dump(lldb_private::Stream &s, bool pretty_print=true) const
lldb::StructuredDataType GetType() const
uint64_t GetUnsignedIntegerValue(uint64_t fail_value=0)
ObjectSP GetObjectForDotSeparatedPath(llvm::StringRef path)
void GetDescription(lldb_private::Stream &s) const override
void SetValue(llvm::StringRef S)
void Serialize(llvm::json::OStream &s) const override
A class which can hold structured data.
static bool IsRecordType(const ObjectSP object_sp)
std::shared_ptr< Generic > GenericSP
std::shared_ptr< UnsignedInteger > UnsignedIntegerSP
std::shared_ptr< Float > FloatSP
std::shared_ptr< Dictionary > DictionarySP
std::shared_ptr< Object > ObjectSP
static ObjectSP ParseJSON(llvm::StringRef json_text)
std::shared_ptr< String > StringSP
std::shared_ptr< Array > ArraySP
std::shared_ptr< Boolean > BooleanSP
static ObjectSP ParseJSONFromFile(const FileSpec &file, Status &error)
std::shared_ptr< SignedInteger > SignedIntegerSP
std::variant< UnsignedIntegerSP, SignedIntegerSP > IntegerSP
A class that represents a running process on the host machine.
Definition: SBAttachInfo.h:14
Definition: SBAddress.h:15
@ eStructuredDataTypeFloat
@ eStructuredDataTypeDictionary
@ eStructuredDataTypeInvalid
@ eStructuredDataTypeInteger
@ eStructuredDataTypeGeneric
@ eStructuredDataTypeArray
@ eStructuredDataTypeSignedInteger
@ eStructuredDataTypeUnsignedInteger
@ eStructuredDataTypeBoolean
@ eStructuredDataTypeString