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