1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
base / trace_event / traced_value.h [blame]
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_TRACE_EVENT_TRACED_VALUE_H_
#define BASE_TRACE_EVENT_TRACED_VALUE_H_
#include <stddef.h>
#include <memory>
#include <sstream>
#include <string>
#include <string_view>
#include <vector>
#include "base/base_export.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ptr_exclusion.h"
#include "base/trace_event/trace_arguments.h"
namespace base {
class Value;
namespace trace_event {
class BASE_EXPORT TracedValue : public ConvertableToTraceFormat {
public:
// TODO(oysteine): |capacity| is not used in any production code. Consider
// removing it.
explicit TracedValue(size_t capacity = 0);
TracedValue(const TracedValue&) = delete;
TracedValue& operator=(const TracedValue&) = delete;
~TracedValue() override;
void EndDictionary();
void EndArray();
// These methods assume that |name| is a long lived "quoted" string.
void SetInteger(const char* name, int value);
void SetDouble(const char* name, double value);
void SetBoolean(const char* name, bool value);
void SetString(const char* name, std::string_view value);
void SetValue(const char* name, TracedValue* value);
void SetPointer(const char* name, const void* value);
void BeginDictionary(const char* name);
void BeginArray(const char* name);
// These, instead, can be safely passed a temporary string.
void SetIntegerWithCopiedName(std::string_view name, int value);
void SetDoubleWithCopiedName(std::string_view name, double value);
void SetBooleanWithCopiedName(std::string_view name, bool value);
void SetStringWithCopiedName(std::string_view name, std::string_view value);
void SetValueWithCopiedName(std::string_view name, TracedValue* value);
void SetPointerWithCopiedName(std::string_view name, const void* value);
void BeginDictionaryWithCopiedName(std::string_view name);
void BeginArrayWithCopiedName(std::string_view name);
void AppendInteger(int);
void AppendDouble(double);
void AppendBoolean(bool);
void AppendString(std::string_view);
void AppendPointer(const void*);
void BeginArray();
void BeginDictionary();
// ConvertableToTraceFormat implementation.
void AppendAsTraceFormat(std::string* out) const override;
bool AppendToProto(ProtoAppender* appender) const override;
// Helper to auto-close an array. The call to |ArrayScope::~ArrayScope| closes
// the array.
//
// To be constructed using:
// |TracedValue::AppendArrayScoped|
// |TracedValue::BeginArrayScoped|
// |TracedValue::BeginArrayScopedWithCopiedName|
//
// |ArrayScope| holds a |TracedValue| pointer which should remain a valid
// pointer until |ArrayScope::~ArrayScope| is called.
//
// |ArrayScope::~ArrayScope| calls |TracedValue::EndArray| (which checks if
// the held |TracedValue*| is in array state).
//
// Example:
// std::unique_ptr<TracedValue> value(new TracedValue());
// {
// auto scope = value->BeginArrayScoped("array_name");
// value->AppendBoolean(false);
// }
class BASE_EXPORT ArrayScope {
public:
ArrayScope(const ArrayScope&) = delete;
ArrayScope(ArrayScope&&) = default;
ArrayScope& operator=(const ArrayScope&) = delete;
ArrayScope& operator=(ArrayScope&&) = default;
~ArrayScope();
private:
explicit ArrayScope(TracedValue* value);
raw_ptr<TracedValue> value_;
friend class TracedValue;
};
// Call |BeginArray| or |BeginArrayWithCopiedName| with no / the same
// parameter and return an |ArrayScope| holding |this|.
[[nodiscard]] ArrayScope AppendArrayScoped();
[[nodiscard]] ArrayScope BeginArrayScoped(const char* name);
[[nodiscard]] ArrayScope BeginArrayScopedWithCopiedName(
std::string_view name);
// Helper to auto-close a dictionary. The call to
// |DictionaryScope::~DictionaryScope| closes the dictionary.
//
// To be constructed using:
// |TracedValue::AppendDictionaryScoped|
// |TracedValue::BeginDictionaryScoped|
// |TracedValue::BeginDictionaryScopedWithCopiedName|
//
// |DictionaryScope| holds a |TracedValue| pointer which should remain a valid
// pointer until |DictionaryScope::~DictionaryScope| is called.
//
// |DictionaryScope::~DictionaryScope| calls |TracedValue::EndDictionary|
// (which checks if the held |TracedValue*| is in dictionary state).
//
// Example:
// std::unique_ptr<TracedValue> value(new TracedValue());
// {
// auto scope = value->BeginDictionaryScoped("dictionary_name");
// value->SetBoolean("my_boolean", false);
// }
class BASE_EXPORT DictionaryScope {
public:
DictionaryScope(const DictionaryScope&) = delete;
DictionaryScope(DictionaryScope&&) = default;
DictionaryScope& operator=(const DictionaryScope&) = delete;
DictionaryScope& operator=(DictionaryScope&&) = default;
~DictionaryScope();
private:
explicit DictionaryScope(TracedValue* value);
raw_ptr<TracedValue> value_;
friend class TracedValue;
};
// Call |BeginDictionary| or |BeginDictionaryWithCopiedName| with no / the
// same parameter and return a |DictionaryScope| holding |this|.
[[nodiscard]] DictionaryScope AppendDictionaryScoped();
[[nodiscard]] DictionaryScope BeginDictionaryScoped(const char* name);
[[nodiscard]] DictionaryScope BeginDictionaryScopedWithCopiedName(
std::string_view name);
class BASE_EXPORT Array;
class BASE_EXPORT Dictionary;
class BASE_EXPORT ValueHolder;
class BASE_EXPORT ArrayItem;
class BASE_EXPORT DictionaryItem;
// Helper to enable easier initialization of |TracedValue|. This is intended
// for quick local debugging as there is overhead of creating
// |std::initializer_list| of name-value objects (in the case of containers
// the value is also a |std::initializer_list|). Generally the helper types
// |TracedValue::Dictionary|, |TracedValue::Array|,
// |TracedValue::DictionaryItem|, |TracedValue::ArrayItem| must be valid as
// well as their internals (e.g., |std::string_view| data should be valid
// when |TracedValue::Build| is called; |TracedValue::Array| or
// |TracedValue::Dictionary| holds a |std::initializer_list| whose underlying
// array needs to be valid when calling |TracedValue::Build|).
//
// Example:
// auto value = TracedValue::Build({
// {"int_var_name", 42},
// {"double_var_name", 3.14},
// {"string_var_name", "hello world"},
// {"empty_array", TracedValue::Array({})},
// {"dictionary", TracedValue::Dictionary({
// {"my_ptr", static_cast<void*>(my_ptr)},
// {"nested_array", TracedValue::Array({1, false, 0.5})},
// })},
// });
static std::unique_ptr<TracedValue> Build(
const std::initializer_list<DictionaryItem> items);
// An |Array| instance represents an array of |ArrayItem| objects. This is a
// helper to allow initializer list like construction of arrays using
// |TracedValue::Build|.
//
// An instance holds an |std::initializer_list<TracedValue::ArrayItem>| and is
// cheap to copy (copying the initializer_list does not copy the underlying
// objects). The underlying array must exist at the time when
// |TracedValue::Build| is called.
class Array {
public:
// This constructor expects that the initializer_list is valid when
// |TracedValue::Build| is called.
Array(const std::initializer_list<ArrayItem> items);
Array(Array&&);
void WriteToValue(TracedValue* value) const;
private:
std::initializer_list<ArrayItem> items_;
};
// A helper to hold a dictionary. Similar to |TracedValue::Array|.
class Dictionary {
public:
// This constructor expects that the initializer_list is valid when
// |TracedValue::Build| is called.
Dictionary(const std::initializer_list<DictionaryItem> items);
Dictionary(Dictionary&&);
void WriteToValue(TracedValue* value) const;
private:
std::initializer_list<DictionaryItem> items_;
};
// A |ValueHolder| holds a single value or a container (int, double... or an
// |Array| / |Dictionary|). Not to be used outside of the context of
// |TracedValue::Build| (has one parameter implicit constructors).
//
// Base class for |TracedValue::ArrayItem| and |TracedValue::DictionaryItem|.
class ValueHolder {
public:
// Implicit constructors allow constructing |DictionaryItem| without having
// to write |{"name", TracedValue::ValueHolder(1)}|.
ValueHolder(int value); // NOLINT(google-explicit-constructor)
ValueHolder(double value); // NOLINT(google-explicit-constructor)
ValueHolder(bool value); // NOLINT(google-explicit-constructor)
ValueHolder(void* value); // NOLINT(google-explicit-constructor)
// std::string_view's backing storage / const char* pointer needs to remain
// valid until TracedValue::Build is called.
// NOLINTNEXTLINE(google-explicit-constructor)
ValueHolder(std::string_view value);
// Create a copy to avoid holding a reference to a non-existing string:
//
// Example:
// TracedValue::Build({{"my_string", std::string("std::string value")}});
// Explanation:
// 1. std::string temporary is passed to the constructor of |ValueHolder|.
// 2. |ValueHolder| is passed to the constructor of |DictionaryItem|.
// 3. |Build| iterates initializer_list of |DictionaryItems|.
//
// If the original |ValueHolder| kept just a reference to the string (or
// a |std::string_view|) then |Build| is undefined behaviour, as it is
// passing a reference to an out-of-scope temporary to
// |TracedValue::SetString|.
// NOLINTNEXTLINE(google-explicit-constructor)
ValueHolder(std::string value);
// Define an explicit overload for const char* to resolve the ambiguity
// between the std::string_view, void*, and bool constructors for string
// literals.
ValueHolder(const char* value); // NOLINT(google-explicit-constructor)
ValueHolder(Array& value); // NOLINT(google-explicit-constructor)
ValueHolder(Dictionary& value); // NOLINT(google-explicit-constructor)
ValueHolder(ValueHolder&&);
protected:
void WriteToValue(TracedValue* value) const;
void WriteToValue(const char* name, TracedValue* value) const;
private:
union KeptValue {
// Copy is handled by the holder (based on
// |TracedValue::ValueHolder::kept_value_type_|).
int int_value;
double double_value;
bool bool_value;
std::string_view string_piece_value;
std::string std_string_value;
// This field is not a raw_ptr<> because it was filtered by the rewriter
// for: #union
RAW_PTR_EXCLUSION void* void_ptr_value;
Array array_value;
Dictionary dictionary_value;
// Default constructor is implicitly deleted because union field has a
// non-trivial default constructor.
KeptValue() {} // NOLINT(modernize-use-equals-default)
~KeptValue() {} // NOLINT(modernize-use-equals-default)
};
// Reimplementing a subset of C++17 std::variant.
enum class KeptValueType {
kIntType,
kDoubleType,
kBoolType,
kStringPieceType,
kStdStringType,
kVoidPtrType,
kArrayType,
kDictionaryType,
};
KeptValue kept_value_;
KeptValueType kept_value_type_;
};
// |ArrayItem| is a |ValueHolder| which can be used to construct an |Array|.
class ArrayItem : public ValueHolder {
public:
// Implicit constructors allow calling |TracedValue::Array({1, true, 3.14})|
// instead of |TracedValue::Array({TracedValue::ArrayItem(1),
// TracedValue::ArrayItem(true), TracedValue::ArrayItem(3.14)})|.
template <typename T>
// NOLINTNEXTLINE(google-explicit-constructor)
ArrayItem(T value) : ValueHolder(value) {}
void WriteToValue(TracedValue* value) const;
};
// |DictionaryItem| instance represents a single name-value pair.
//
// |name| is assumed to be a long lived "quoted" string.
class DictionaryItem : public ValueHolder {
public:
// These constructors assume that |name| is a long lived "quoted" string.
template <typename T>
DictionaryItem(const char* name, T value)
: ValueHolder(value), name_(name) {}
void WriteToValue(TracedValue* value) const;
private:
const char* name_;
};
// A custom serialization class can be supplied by implementing the
// Writer interface and supplying a factory class to SetWriterFactoryCallback.
// Primarily used by Perfetto to write TracedValues directly into its proto
// format, which lets us do a direct memcpy() in AppendToProto() rather than
// a JSON serialization step in AppendAsTraceFormat.
class BASE_EXPORT Writer {
public:
virtual ~Writer() = default;
virtual void BeginArray() = 0;
virtual void BeginDictionary() = 0;
virtual void EndDictionary() = 0;
virtual void EndArray() = 0;
// These methods assume that |name| is a long lived "quoted" string.
virtual void SetInteger(const char* name, int value) = 0;
virtual void SetDouble(const char* name, double value) = 0;
virtual void SetBoolean(const char* name, bool value) = 0;
virtual void SetString(const char* name, std::string_view value) = 0;
virtual void SetValue(const char* name, Writer* value) = 0;
virtual void BeginDictionary(const char* name) = 0;
virtual void BeginArray(const char* name) = 0;
// These, instead, can be safely passed a temporary string.
virtual void SetIntegerWithCopiedName(std::string_view name, int value) = 0;
virtual void SetDoubleWithCopiedName(std::string_view name,
double value) = 0;
virtual void SetBooleanWithCopiedName(std::string_view name,
bool value) = 0;
virtual void SetStringWithCopiedName(std::string_view name,
std::string_view value) = 0;
virtual void SetValueWithCopiedName(std::string_view name,
Writer* value) = 0;
virtual void BeginDictionaryWithCopiedName(std::string_view name) = 0;
virtual void BeginArrayWithCopiedName(std::string_view name) = 0;
virtual void AppendInteger(int) = 0;
virtual void AppendDouble(double) = 0;
virtual void AppendBoolean(bool) = 0;
virtual void AppendString(std::string_view) = 0;
virtual void AppendAsTraceFormat(std::string* out) const = 0;
virtual bool AppendToProto(ProtoAppender* appender);
virtual bool IsPickleWriter() const = 0;
virtual bool IsProtoWriter() const = 0;
};
typedef std::unique_ptr<Writer> (*WriterFactoryCallback)(size_t capacity);
static void SetWriterFactoryCallback(WriterFactoryCallback callback);
protected:
TracedValue(size_t capacity, bool forced_json);
std::unique_ptr<base::Value> ToBaseValue() const;
private:
mutable std::unique_ptr<Writer> writer_;
#ifndef NDEBUG
// In debug builds checks the pairings of {Start,End}{Dictionary,Array}
std::vector<bool> nesting_stack_;
#endif
};
// TracedValue that is convertable to JSON format. This has lower performance
// than the default TracedValue in production code, and should be used only for
// testing and debugging. Should be avoided in tracing. It's for
// testing/debugging code calling value dumping function designed for tracing,
// like the following:
//
// TracedValueJSON value;
// AsValueInto(&value); // which is designed for tracing.
// return value.ToJSON();
//
// If the code is merely for testing/debugging, base::Value should be used
// instead.
class BASE_EXPORT TracedValueJSON : public TracedValue {
public:
explicit TracedValueJSON(size_t capacity = 0)
: TracedValue(capacity, /*forced_josn*/ true) {}
using TracedValue::ToBaseValue;
// Converts the value into a JSON string without formatting. Suitable for
// printing a simple value or printing a value in a single line context.
std::string ToJSON() const;
// Converts the value into a formatted JSON string, with indentation, spaces
// and new lines for better human readability of complex values.
std::string ToFormattedJSON() const;
};
} // namespace trace_event
} // namespace base
#endif // BASE_TRACE_EVENT_TRACED_VALUE_H_