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 429 430 431 432 433 434 435
|
// 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 <vector>
#include "base/base_export.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ptr_exclusion.h"
#include "base/strings/string_piece.h"
#include "base/trace_event/trace_arguments.h"
namespace base {
class TraceEventMemoryOverhead;
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, base::StringPiece value);
void SetValue(const char* name, TracedValue* value);
void SetPointer(const char* name, void* value);
void BeginDictionary(const char* name);
void BeginArray(const char* name);
// These, instead, can be safely passed a temporary string.
void SetIntegerWithCopiedName(base::StringPiece name, int value);
void SetDoubleWithCopiedName(base::StringPiece name, double value);
void SetBooleanWithCopiedName(base::StringPiece name, bool value);
void SetStringWithCopiedName(base::StringPiece name, base::StringPiece value);
void SetValueWithCopiedName(base::StringPiece name, TracedValue* value);
void SetPointerWithCopiedName(base::StringPiece name, void* value);
void BeginDictionaryWithCopiedName(base::StringPiece name);
void BeginArrayWithCopiedName(base::StringPiece name);
void AppendInteger(int);
void AppendDouble(double);
void AppendBoolean(bool);
void AppendString(base::StringPiece);
void AppendPointer(void*);
void BeginArray();
void BeginDictionary();
// ConvertableToTraceFormat implementation.
void AppendAsTraceFormat(std::string* out) const override;
bool AppendToProto(ProtoAppender* appender) const override;
void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead) 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(
base::StringPiece 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(
base::StringPiece 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., |base::StringPiece| 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)
// StringPiece's backing storage / const char* pointer needs to remain valid
// until TracedValue::Build is called.
// NOLINTNEXTLINE(google-explicit-constructor)
ValueHolder(base::StringPiece 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 |base::StringPiece|) 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 base::StringPiece, 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;
base::StringPiece 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, base::StringPiece 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(base::StringPiece name,
int value) = 0;
virtual void SetDoubleWithCopiedName(base::StringPiece name,
double value) = 0;
virtual void SetBooleanWithCopiedName(base::StringPiece name,
bool value) = 0;
virtual void SetStringWithCopiedName(base::StringPiece name,
base::StringPiece value) = 0;
virtual void SetValueWithCopiedName(base::StringPiece name,
Writer* value) = 0;
virtual void BeginDictionaryWithCopiedName(base::StringPiece name) = 0;
virtual void BeginArrayWithCopiedName(base::StringPiece name) = 0;
virtual void AppendInteger(int) = 0;
virtual void AppendDouble(double) = 0;
virtual void AppendBoolean(bool) = 0;
virtual void AppendString(base::StringPiece) = 0;
virtual void AppendAsTraceFormat(std::string* out) const = 0;
virtual bool AppendToProto(ProtoAppender* appender);
virtual void EstimateTraceMemoryOverhead(
TraceEventMemoryOverhead* overhead) = 0;
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_
|