|
14 | 14 |
|
15 | 15 | #include "src/trace_processor/perfetto_sql/intrinsics/functions/args.h"
|
16 | 16 |
|
17 |
| -#include "perfetto/ext/base/dynamic_string_writer.h" |
| 17 | +#include "perfetto/ext/base/string_utils.h" |
18 | 18 | #include "src/trace_processor/sqlite/bindings/sqlite_result.h"
|
19 | 19 | #include "src/trace_processor/sqlite/bindings/sqlite_type.h"
|
20 | 20 | #include "src/trace_processor/util/args_utils.h"
|
| 21 | +#include "src/trace_processor/util/json_writer.h" |
21 | 22 |
|
22 | 23 | namespace perfetto::trace_processor {
|
23 | 24 | namespace {
|
24 |
| -// We care about the argument order, so we can't use jsoncpp here. |
25 |
| -void WriteAsJson(const ArgNode& node, |
26 |
| - const TraceStorage* storage, |
27 |
| - base::DynamicStringWriter& writer) { |
28 |
| - switch (node.GetType()) { |
29 |
| - case ArgNode::Type::kPrimitive: { |
30 |
| - Variadic v = node.GetPrimitiveValue(); |
31 |
| - switch (v.type) { |
32 |
| - case Variadic::Type::kNull: |
33 |
| - writer.AppendLiteral("null"); |
34 |
| - break; |
35 |
| - case Variadic::Type::kBool: |
36 |
| - writer.AppendString(v.bool_value ? "true" : "false"); |
37 |
| - break; |
38 |
| - case Variadic::Type::kInt: |
39 |
| - writer.AppendInt(v.int_value); |
40 |
| - break; |
41 |
| - case Variadic::Type::kUint: |
42 |
| - writer.AppendUnsignedInt(v.uint_value); |
43 |
| - break; |
44 |
| - case Variadic::Type::kReal: |
45 |
| - if (std::isnan(v.real_value)) { |
46 |
| - writer.AppendLiteral("\"NaN\""); |
47 |
| - } else if (std::isinf(v.real_value) && v.real_value > 0) { |
48 |
| - writer.AppendLiteral("\"Infinity\""); |
49 |
| - } else if (std::isinf(v.real_value) && v.real_value < 0) { |
50 |
| - writer.AppendLiteral("\"-Infinity\""); |
51 |
| - } else { |
52 |
| - writer.AppendDouble(v.real_value); |
53 |
| - } |
54 |
| - break; |
55 |
| - case Variadic::Type::kString: |
56 |
| - writer.AppendChar('"'); |
57 |
| - for (const char* p = storage->GetString(v.string_value).c_str(); *p; |
58 |
| - p++) { |
59 |
| - unsigned char c = static_cast<unsigned char>(*p); |
60 |
| - if (*p == '"') { |
61 |
| - writer.AppendLiteral("\\\""); |
62 |
| - } else if (*p == '\\') { |
63 |
| - writer.AppendLiteral("\\\\"); |
64 |
| - } else if (*p == '\n') { |
65 |
| - writer.AppendLiteral("\\n"); |
66 |
| - } else if (*p == '\r') { |
67 |
| - writer.AppendLiteral("\\r"); |
68 |
| - } else if (*p == '\t') { |
69 |
| - writer.AppendLiteral("\\t"); |
70 |
| - } else if (c < 0x20) { |
71 |
| - // Escape all control characters below 0x20 in \uXXXX format |
72 |
| - writer.AppendLiteral("\\u00"); |
73 |
| - writer.AppendChar("0123456789abcdef"[c >> 4]); |
74 |
| - writer.AppendChar("0123456789abcdef"[c & 0xf]); |
75 |
| - } else { |
76 |
| - writer.AppendChar(*p); |
77 |
| - } |
78 |
| - } |
79 |
| - writer.AppendChar('"'); |
80 |
| - break; |
81 |
| - case Variadic::Type::kPointer: |
82 |
| - writer.AppendChar('"'); |
83 |
| - writer.AppendString( |
84 |
| - base::StringView(base::Uint64ToHexString(v.pointer_value))); |
85 |
| - writer.AppendChar('"'); |
86 |
| - break; |
87 |
| - case Variadic::Type::kJson: |
88 |
| - writer.AppendString(storage->GetString(v.json_value).c_str()); |
89 |
| - break; |
90 |
| - } |
| 25 | + |
| 26 | +void WriteVariadic(const Variadic& v, |
| 27 | + const TraceStorage* storage, |
| 28 | + JsonValueWriter&& writer) { |
| 29 | + switch (v.type) { |
| 30 | + case Variadic::Type::kNull: |
| 31 | + std::move(writer).WriteNull(); |
91 | 32 | break;
|
92 |
| - } |
93 |
| - case ArgNode::Type::kArray: { |
94 |
| - writer.AppendChar('['); |
95 |
| - const auto& array = node.GetArray(); |
96 |
| - for (size_t i = 0; i < array.size(); i++) { |
97 |
| - if (i > 0) |
98 |
| - writer.AppendChar(','); |
99 |
| - WriteAsJson(array[i], storage, writer); |
100 |
| - } |
101 |
| - writer.AppendChar(']'); |
| 33 | + case Variadic::Type::kBool: |
| 34 | + std::move(writer).WriteBool(v.bool_value); |
102 | 35 | break;
|
103 |
| - } |
104 |
| - case ArgNode::Type::kDict: { |
105 |
| - writer.AppendChar('{'); |
106 |
| - const auto& dict = node.GetDict(); |
107 |
| - for (size_t i = 0; i < dict.size(); i++) { |
108 |
| - if (i > 0) |
109 |
| - writer.AppendChar(','); |
110 |
| - writer.AppendChar('"'); |
111 |
| - writer.AppendString(dict[i].first.c_str()); |
112 |
| - writer.AppendLiteral("\":"); |
113 |
| - WriteAsJson(dict[i].second, storage, writer); |
114 |
| - } |
115 |
| - writer.AppendChar('}'); |
| 36 | + case Variadic::Type::kInt: |
| 37 | + std::move(writer).WriteInt(v.int_value); |
| 38 | + break; |
| 39 | + case Variadic::Type::kUint: |
| 40 | + std::move(writer).WriteUint(v.uint_value); |
| 41 | + break; |
| 42 | + case Variadic::Type::kReal: |
| 43 | + std::move(writer).WriteDouble(v.real_value); |
| 44 | + break; |
| 45 | + case Variadic::Type::kString: |
| 46 | + std::move(writer).WriteString(storage->GetString(v.string_value).c_str()); |
| 47 | + break; |
| 48 | + case Variadic::Type::kPointer: { |
| 49 | + std::string hex = base::Uint64ToHexStringNoPrefix(v.pointer_value); |
| 50 | + std::move(writer).WriteString(hex); |
116 | 51 | break;
|
117 | 52 | }
|
| 53 | + case Variadic::Type::kJson: |
| 54 | + // For JSON values, we need to parse and reconstruct them properly |
| 55 | + // For now, just treat as string |
| 56 | + std::move(writer).WriteString(storage->GetString(v.json_value).c_str()); |
| 57 | + break; |
118 | 58 | }
|
119 | 59 | }
|
| 60 | + |
| 61 | +void WriteArgNode(const ArgNode& node, |
| 62 | + const TraceStorage* storage, |
| 63 | + JsonValueWriter&& writer); |
| 64 | + |
| 65 | +void WriteArgNode(const ArgNode& node, |
| 66 | + const TraceStorage* storage, |
| 67 | + JsonArrayWriter& writer); |
| 68 | + |
| 69 | +void WriteArgNode(const ArgNode& node, |
| 70 | + const TraceStorage* storage, |
| 71 | + JsonDictWriter& writer, |
| 72 | + std::string_view key); |
| 73 | + |
| 74 | +void WriteArgNode(const ArgNode& node, |
| 75 | + const TraceStorage* storage, |
| 76 | + JsonValueWriter&& writer) { |
| 77 | + switch (node.GetType()) { |
| 78 | + case ArgNode::Type::kPrimitive: |
| 79 | + WriteVariadic(node.GetPrimitiveValue(), storage, std::move(writer)); |
| 80 | + break; |
| 81 | + case ArgNode::Type::kArray: |
| 82 | + std::move(writer).WriteArray([&node, storage](JsonArrayWriter& arr) { |
| 83 | + for (const auto& child : node.GetArray()) { |
| 84 | + WriteArgNode(child, storage, arr); |
| 85 | + } |
| 86 | + }); |
| 87 | + break; |
| 88 | + case ArgNode::Type::kDict: |
| 89 | + std::move(writer).WriteDict([&node, storage](JsonDictWriter& dict) { |
| 90 | + for (const auto& [k, v] : node.GetDict()) { |
| 91 | + WriteArgNode(v, storage, dict, k); |
| 92 | + } |
| 93 | + }); |
| 94 | + break; |
| 95 | + } |
| 96 | +} |
| 97 | + |
| 98 | +void WriteArgNode(const ArgNode& node, |
| 99 | + const TraceStorage* storage, |
| 100 | + JsonArrayWriter& writer) { |
| 101 | + writer.Append([&node, storage](JsonValueWriter&& value_writer) { |
| 102 | + WriteArgNode(node, storage, std::move(value_writer)); |
| 103 | + }); |
| 104 | +} |
| 105 | + |
| 106 | +void WriteArgNode(const ArgNode& node, |
| 107 | + const TraceStorage* storage, |
| 108 | + JsonDictWriter& writer, |
| 109 | + std::string_view key) { |
| 110 | + writer.Add(key, [&node, storage](JsonValueWriter&& value_writer) { |
| 111 | + WriteArgNode(node, storage, std::move(value_writer)); |
| 112 | + }); |
| 113 | +} |
| 114 | + |
120 | 115 | } // namespace
|
121 | 116 |
|
122 | 117 | // static
|
@@ -198,9 +193,13 @@ void PrintArgs::Step(sqlite3_context* ctx, int, sqlite3_value** argv) {
|
198 | 193 | return sqlite::result::Error(ctx, result.c_message());
|
199 | 194 | }
|
200 | 195 | }
|
201 |
| - base::DynamicStringWriter writer; |
202 |
| - WriteAsJson(arg_set.root(), storage, writer); |
203 |
| - std::string result = writer.GetStringView().ToStdString(); |
| 196 | + std::string result = write([&](JsonValueWriter&& json_writer) { |
| 197 | + std::move(json_writer).WriteDict([&](JsonDictWriter& writer) { |
| 198 | + for (const auto& [key, value] : arg_set.root().GetDict()) { |
| 199 | + WriteArgNode(value, storage, writer, key); |
| 200 | + } |
| 201 | + }); |
| 202 | + }); |
204 | 203 | return sqlite::result::TransientString(ctx, result.c_str());
|
205 | 204 | }
|
206 | 205 |
|
|
0 commit comments