xref: /aosp_15_r20/external/perfetto/include/perfetto/tracing/traced_value.h (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1*6dbdd20aSAndroid Build Coastguard Worker /*
2*6dbdd20aSAndroid Build Coastguard Worker  * Copyright (C) 2021 The Android Open Source Project
3*6dbdd20aSAndroid Build Coastguard Worker  *
4*6dbdd20aSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*6dbdd20aSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*6dbdd20aSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*6dbdd20aSAndroid Build Coastguard Worker  *
8*6dbdd20aSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*6dbdd20aSAndroid Build Coastguard Worker  *
10*6dbdd20aSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*6dbdd20aSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*6dbdd20aSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*6dbdd20aSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*6dbdd20aSAndroid Build Coastguard Worker  * limitations under the License.
15*6dbdd20aSAndroid Build Coastguard Worker  */
16*6dbdd20aSAndroid Build Coastguard Worker 
17*6dbdd20aSAndroid Build Coastguard Worker #ifndef INCLUDE_PERFETTO_TRACING_TRACED_VALUE_H_
18*6dbdd20aSAndroid Build Coastguard Worker #define INCLUDE_PERFETTO_TRACING_TRACED_VALUE_H_
19*6dbdd20aSAndroid Build Coastguard Worker 
20*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/compiler.h"
21*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/export.h"
22*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/template_util.h"
23*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/protozero/message.h"
24*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/protozero/proto_utils.h"
25*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/tracing/internal/checked_scope.h"
26*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/tracing/string_helpers.h"
27*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/tracing/traced_value_forward.h"
28*6dbdd20aSAndroid Build Coastguard Worker 
29*6dbdd20aSAndroid Build Coastguard Worker #include <memory>
30*6dbdd20aSAndroid Build Coastguard Worker #include <string>
31*6dbdd20aSAndroid Build Coastguard Worker #include <string_view>
32*6dbdd20aSAndroid Build Coastguard Worker #include <type_traits>
33*6dbdd20aSAndroid Build Coastguard Worker #include <utility>
34*6dbdd20aSAndroid Build Coastguard Worker 
35*6dbdd20aSAndroid Build Coastguard Worker namespace perfetto {
36*6dbdd20aSAndroid Build Coastguard Worker 
37*6dbdd20aSAndroid Build Coastguard Worker namespace protos {
38*6dbdd20aSAndroid Build Coastguard Worker namespace pbzero {
39*6dbdd20aSAndroid Build Coastguard Worker class DebugAnnotation;
40*6dbdd20aSAndroid Build Coastguard Worker }
41*6dbdd20aSAndroid Build Coastguard Worker }  // namespace protos
42*6dbdd20aSAndroid Build Coastguard Worker 
43*6dbdd20aSAndroid Build Coastguard Worker class DebugAnnotation;
44*6dbdd20aSAndroid Build Coastguard Worker class EventContext;
45*6dbdd20aSAndroid Build Coastguard Worker 
46*6dbdd20aSAndroid Build Coastguard Worker // These classes provide a JSON-inspired way to write structed data into traces.
47*6dbdd20aSAndroid Build Coastguard Worker //
48*6dbdd20aSAndroid Build Coastguard Worker // Each TracedValue can be consumed exactly once to write a value into a trace
49*6dbdd20aSAndroid Build Coastguard Worker // using one of the Write* methods.
50*6dbdd20aSAndroid Build Coastguard Worker //
51*6dbdd20aSAndroid Build Coastguard Worker // Write* methods fall into two categories:
52*6dbdd20aSAndroid Build Coastguard Worker // - Primitive types (int, string, bool, double, etc): they just write the
53*6dbdd20aSAndroid Build Coastguard Worker //   provided value, consuming the TracedValue in the process.
54*6dbdd20aSAndroid Build Coastguard Worker // - Complex types (arrays and dicts): they consume the TracedValue and
55*6dbdd20aSAndroid Build Coastguard Worker //   return a corresponding scoped object (TracedArray or TracedDictionary).
56*6dbdd20aSAndroid Build Coastguard Worker //   This scope then can be used to write multiple items into the container:
57*6dbdd20aSAndroid Build Coastguard Worker //   TracedArray::AppendItem and TracedDictionary::AddItem return a new
58*6dbdd20aSAndroid Build Coastguard Worker //   TracedValue which then can be used to write an element of the
59*6dbdd20aSAndroid Build Coastguard Worker //   dictionary or array.
60*6dbdd20aSAndroid Build Coastguard Worker //
61*6dbdd20aSAndroid Build Coastguard Worker // To define how a custom class should be written into the trace, users should
62*6dbdd20aSAndroid Build Coastguard Worker // define one of the two following functions:
63*6dbdd20aSAndroid Build Coastguard Worker // - Foo::WriteIntoTrace(TracedValue) const
64*6dbdd20aSAndroid Build Coastguard Worker //   (preferred for code which depends on perfetto directly)
65*6dbdd20aSAndroid Build Coastguard Worker // - perfetto::TraceFormatTraits<T>::WriteIntoTrace(
66*6dbdd20aSAndroid Build Coastguard Worker //       TracedValue, const T&);
67*6dbdd20aSAndroid Build Coastguard Worker //   (should be used if T is defined in a library which doesn't know anything
68*6dbdd20aSAndroid Build Coastguard Worker //   about tracing).
69*6dbdd20aSAndroid Build Coastguard Worker //
70*6dbdd20aSAndroid Build Coastguard Worker //
71*6dbdd20aSAndroid Build Coastguard Worker // After defining a conversion method, the object can be used directly as a
72*6dbdd20aSAndroid Build Coastguard Worker // TRACE_EVENT argument:
73*6dbdd20aSAndroid Build Coastguard Worker //
74*6dbdd20aSAndroid Build Coastguard Worker // Foo foo;
75*6dbdd20aSAndroid Build Coastguard Worker // TRACE_EVENT("cat", "Event", "arg", foo);
76*6dbdd20aSAndroid Build Coastguard Worker //
77*6dbdd20aSAndroid Build Coastguard Worker // Examples:
78*6dbdd20aSAndroid Build Coastguard Worker //
79*6dbdd20aSAndroid Build Coastguard Worker // TRACE_EVENT("cat", "event", "params", [&](perfetto::TracedValue context)
80*6dbdd20aSAndroid Build Coastguard Worker // {
81*6dbdd20aSAndroid Build Coastguard Worker //   auto dict = std::move(context).WriteDictionary();
82*6dbdd20aSAndroid Build Coastguard Worker //   dict->Add("param1", param1);
83*6dbdd20aSAndroid Build Coastguard Worker //   dict->Add("param2", param2);
84*6dbdd20aSAndroid Build Coastguard Worker //   ...
85*6dbdd20aSAndroid Build Coastguard Worker //   dict->Add("paramN", paramN);
86*6dbdd20aSAndroid Build Coastguard Worker //
87*6dbdd20aSAndroid Build Coastguard Worker //   {
88*6dbdd20aSAndroid Build Coastguard Worker //     auto inner_array = dict->AddArray("inner");
89*6dbdd20aSAndroid Build Coastguard Worker //     inner_array->Append(value1);
90*6dbdd20aSAndroid Build Coastguard Worker //     inner_array->Append(value2);
91*6dbdd20aSAndroid Build Coastguard Worker //   }
92*6dbdd20aSAndroid Build Coastguard Worker // });
93*6dbdd20aSAndroid Build Coastguard Worker //
94*6dbdd20aSAndroid Build Coastguard Worker // template <typename T>
95*6dbdd20aSAndroid Build Coastguard Worker // TraceFormatTraits<std::optional<T>>::WriteIntoTrace(
96*6dbdd20aSAndroid Build Coastguard Worker //    TracedValue context, const std::optional<T>& value) {
97*6dbdd20aSAndroid Build Coastguard Worker //  if (!value) {
98*6dbdd20aSAndroid Build Coastguard Worker //    std::move(context).WritePointer(nullptr);
99*6dbdd20aSAndroid Build Coastguard Worker //    return;
100*6dbdd20aSAndroid Build Coastguard Worker //  }
101*6dbdd20aSAndroid Build Coastguard Worker //  perfetto::WriteIntoTrace(std::move(context), *value);
102*6dbdd20aSAndroid Build Coastguard Worker // }
103*6dbdd20aSAndroid Build Coastguard Worker //
104*6dbdd20aSAndroid Build Coastguard Worker // template <typename T>
105*6dbdd20aSAndroid Build Coastguard Worker // TraceFormatTraits<std::vector<T>>::WriteIntoTrace(
106*6dbdd20aSAndroid Build Coastguard Worker //    TracedValue context, const std::array<T>& value) {
107*6dbdd20aSAndroid Build Coastguard Worker //  auto array = std::move(context).WriteArray();
108*6dbdd20aSAndroid Build Coastguard Worker //  for (const auto& item: value) {
109*6dbdd20aSAndroid Build Coastguard Worker //    array_scope.Append(item);
110*6dbdd20aSAndroid Build Coastguard Worker //  }
111*6dbdd20aSAndroid Build Coastguard Worker // }
112*6dbdd20aSAndroid Build Coastguard Worker //
113*6dbdd20aSAndroid Build Coastguard Worker // class Foo {
114*6dbdd20aSAndroid Build Coastguard Worker //   void WriteIntoTrace(TracedValue context) const {
115*6dbdd20aSAndroid Build Coastguard Worker //     auto dict = std::move(context).WriteDictionary();
116*6dbdd20aSAndroid Build Coastguard Worker //     dict->Set("key", 42);
117*6dbdd20aSAndroid Build Coastguard Worker //     dict->Set("foo", "bar");
118*6dbdd20aSAndroid Build Coastguard Worker //     dict->Set("member", member_);
119*6dbdd20aSAndroid Build Coastguard Worker //   }
120*6dbdd20aSAndroid Build Coastguard Worker // }
121*6dbdd20aSAndroid Build Coastguard Worker namespace internal {
122*6dbdd20aSAndroid Build Coastguard Worker // TODO(altimin): Currently EventContext can be null due the need to support
123*6dbdd20aSAndroid Build Coastguard Worker // TracedValue-based serialisation with the Chrome's TraceLog. After this is
124*6dbdd20aSAndroid Build Coastguard Worker // gone, the second parameter should be changed to EventContext&.
125*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_EXPORT_COMPONENT TracedValue
126*6dbdd20aSAndroid Build Coastguard Worker CreateTracedValueFromProto(protos::pbzero::DebugAnnotation*,
127*6dbdd20aSAndroid Build Coastguard Worker                            EventContext* = nullptr);
128*6dbdd20aSAndroid Build Coastguard Worker }
129*6dbdd20aSAndroid Build Coastguard Worker 
130*6dbdd20aSAndroid Build Coastguard Worker class PERFETTO_EXPORT_COMPONENT TracedValue {
131*6dbdd20aSAndroid Build Coastguard Worker  public:
132*6dbdd20aSAndroid Build Coastguard Worker   TracedValue(const TracedValue&) = delete;
133*6dbdd20aSAndroid Build Coastguard Worker   TracedValue& operator=(const TracedValue&) = delete;
134*6dbdd20aSAndroid Build Coastguard Worker   TracedValue& operator=(TracedValue&&) = delete;
135*6dbdd20aSAndroid Build Coastguard Worker   TracedValue(TracedValue&&);
136*6dbdd20aSAndroid Build Coastguard Worker   ~TracedValue();
137*6dbdd20aSAndroid Build Coastguard Worker 
138*6dbdd20aSAndroid Build Coastguard Worker   // TracedValue represents a context into which a single value can be written
139*6dbdd20aSAndroid Build Coastguard Worker   // (either by writing it directly for primitive types, or by creating a
140*6dbdd20aSAndroid Build Coastguard Worker   // TracedArray or TracedDictionary for the complex types). This is enforced
141*6dbdd20aSAndroid Build Coastguard Worker   // by allowing Write* methods to be called only on rvalue references.
142*6dbdd20aSAndroid Build Coastguard Worker 
143*6dbdd20aSAndroid Build Coastguard Worker   void WriteInt64(int64_t value) &&;
144*6dbdd20aSAndroid Build Coastguard Worker   void WriteUInt64(uint64_t value) &&;
145*6dbdd20aSAndroid Build Coastguard Worker   void WriteDouble(double value) &&;
146*6dbdd20aSAndroid Build Coastguard Worker   void WriteBoolean(bool value) &&;
147*6dbdd20aSAndroid Build Coastguard Worker   void WriteString(const char*) &&;
148*6dbdd20aSAndroid Build Coastguard Worker   void WriteString(const char*, size_t len) &&;
149*6dbdd20aSAndroid Build Coastguard Worker   void WriteString(const std::string&) &&;
150*6dbdd20aSAndroid Build Coastguard Worker   void WriteString(std::string_view) &&;
151*6dbdd20aSAndroid Build Coastguard Worker   void WritePointer(const void* value) &&;
152*6dbdd20aSAndroid Build Coastguard Worker   template <typename MessageType>
153*6dbdd20aSAndroid Build Coastguard Worker   TracedProto<MessageType> WriteProto() &&;
154*6dbdd20aSAndroid Build Coastguard Worker 
155*6dbdd20aSAndroid Build Coastguard Worker   // Rules for writing nested dictionaries and arrays:
156*6dbdd20aSAndroid Build Coastguard Worker   // - Only one scope (TracedArray, TracedDictionary or TracedValue) can be
157*6dbdd20aSAndroid Build Coastguard Worker   // active at the same time. It's only allowed to call methods on the active
158*6dbdd20aSAndroid Build Coastguard Worker   // scope.
159*6dbdd20aSAndroid Build Coastguard Worker   // - When a scope creates a nested scope, the new scope becomes active.
160*6dbdd20aSAndroid Build Coastguard Worker   // - When a scope is destroyed, its parent scope becomes active again.
161*6dbdd20aSAndroid Build Coastguard Worker   //
162*6dbdd20aSAndroid Build Coastguard Worker   // Typically users will have to create a scope only at the beginning of a
163*6dbdd20aSAndroid Build Coastguard Worker   // conversion function and this scope should be destroyed at the end of it.
164*6dbdd20aSAndroid Build Coastguard Worker   // TracedArray::Append and TracedDictionary::Add create, write and complete
165*6dbdd20aSAndroid Build Coastguard Worker   // inner scopes automatically.
166*6dbdd20aSAndroid Build Coastguard Worker 
167*6dbdd20aSAndroid Build Coastguard Worker   // Scope which allows multiple values to be appended.
168*6dbdd20aSAndroid Build Coastguard Worker   TracedArray WriteArray() && PERFETTO_WARN_UNUSED_RESULT;
169*6dbdd20aSAndroid Build Coastguard Worker 
170*6dbdd20aSAndroid Build Coastguard Worker   // Scope which allows multiple key-value pairs to be added.
171*6dbdd20aSAndroid Build Coastguard Worker   TracedDictionary WriteDictionary() && PERFETTO_WARN_UNUSED_RESULT;
172*6dbdd20aSAndroid Build Coastguard Worker 
173*6dbdd20aSAndroid Build Coastguard Worker  private:
174*6dbdd20aSAndroid Build Coastguard Worker   friend class TracedArray;
175*6dbdd20aSAndroid Build Coastguard Worker   friend class TracedDictionary;
176*6dbdd20aSAndroid Build Coastguard Worker   friend TracedValue internal::CreateTracedValueFromProto(
177*6dbdd20aSAndroid Build Coastguard Worker       protos::pbzero::DebugAnnotation*,
178*6dbdd20aSAndroid Build Coastguard Worker       EventContext*);
179*6dbdd20aSAndroid Build Coastguard Worker 
180*6dbdd20aSAndroid Build Coastguard Worker   static TracedValue CreateFromProto(protos::pbzero::DebugAnnotation* proto,
181*6dbdd20aSAndroid Build Coastguard Worker                                      EventContext* event_context = nullptr);
182*6dbdd20aSAndroid Build Coastguard Worker 
TracedValue(protos::pbzero::DebugAnnotation * annotation,EventContext * event_context,internal::CheckedScope * parent_scope)183*6dbdd20aSAndroid Build Coastguard Worker   inline TracedValue(protos::pbzero::DebugAnnotation* annotation,
184*6dbdd20aSAndroid Build Coastguard Worker                      EventContext* event_context,
185*6dbdd20aSAndroid Build Coastguard Worker                      internal::CheckedScope* parent_scope)
186*6dbdd20aSAndroid Build Coastguard Worker       : annotation_(annotation),
187*6dbdd20aSAndroid Build Coastguard Worker         event_context_(event_context),
188*6dbdd20aSAndroid Build Coastguard Worker         checked_scope_(parent_scope) {}
189*6dbdd20aSAndroid Build Coastguard Worker 
190*6dbdd20aSAndroid Build Coastguard Worker   protozero::Message* WriteProtoInternal(const char* name);
191*6dbdd20aSAndroid Build Coastguard Worker 
192*6dbdd20aSAndroid Build Coastguard Worker   // Temporary support for perfetto::DebugAnnotation C++ class before it's going
193*6dbdd20aSAndroid Build Coastguard Worker   // to be replaced by TracedValue.
194*6dbdd20aSAndroid Build Coastguard Worker   // TODO(altimin): Convert v8 to use TracedValue directly and delete it.
195*6dbdd20aSAndroid Build Coastguard Worker   friend class DebugAnnotation;
196*6dbdd20aSAndroid Build Coastguard Worker 
197*6dbdd20aSAndroid Build Coastguard Worker   protos::pbzero::DebugAnnotation* const annotation_ = nullptr;
198*6dbdd20aSAndroid Build Coastguard Worker   EventContext* const event_context_ = nullptr;
199*6dbdd20aSAndroid Build Coastguard Worker 
200*6dbdd20aSAndroid Build Coastguard Worker   internal::CheckedScope checked_scope_;
201*6dbdd20aSAndroid Build Coastguard Worker };
202*6dbdd20aSAndroid Build Coastguard Worker 
203*6dbdd20aSAndroid Build Coastguard Worker template <typename MessageType>
WriteProto()204*6dbdd20aSAndroid Build Coastguard Worker TracedProto<MessageType> TracedValue::WriteProto() && {
205*6dbdd20aSAndroid Build Coastguard Worker   return TracedProto<MessageType>(
206*6dbdd20aSAndroid Build Coastguard Worker       static_cast<MessageType*>(WriteProtoInternal(MessageType::GetName())),
207*6dbdd20aSAndroid Build Coastguard Worker       event_context_);
208*6dbdd20aSAndroid Build Coastguard Worker }
209*6dbdd20aSAndroid Build Coastguard Worker 
210*6dbdd20aSAndroid Build Coastguard Worker class PERFETTO_EXPORT_COMPONENT TracedArray {
211*6dbdd20aSAndroid Build Coastguard Worker  public:
212*6dbdd20aSAndroid Build Coastguard Worker   // implicit
213*6dbdd20aSAndroid Build Coastguard Worker   TracedArray(TracedValue);
214*6dbdd20aSAndroid Build Coastguard Worker 
215*6dbdd20aSAndroid Build Coastguard Worker   TracedArray(const TracedArray&) = delete;
216*6dbdd20aSAndroid Build Coastguard Worker   TracedArray& operator=(const TracedArray&) = delete;
217*6dbdd20aSAndroid Build Coastguard Worker   TracedArray& operator=(TracedArray&&) = delete;
218*6dbdd20aSAndroid Build Coastguard Worker   TracedArray(TracedArray&&) = default;
219*6dbdd20aSAndroid Build Coastguard Worker   ~TracedArray() = default;
220*6dbdd20aSAndroid Build Coastguard Worker 
221*6dbdd20aSAndroid Build Coastguard Worker   TracedValue AppendItem();
222*6dbdd20aSAndroid Build Coastguard Worker 
223*6dbdd20aSAndroid Build Coastguard Worker   template <typename T>
Append(T && value)224*6dbdd20aSAndroid Build Coastguard Worker   void Append(T&& value) {
225*6dbdd20aSAndroid Build Coastguard Worker     WriteIntoTracedValue(AppendItem(), std::forward<T>(value));
226*6dbdd20aSAndroid Build Coastguard Worker   }
227*6dbdd20aSAndroid Build Coastguard Worker 
228*6dbdd20aSAndroid Build Coastguard Worker   TracedDictionary AppendDictionary() PERFETTO_WARN_UNUSED_RESULT;
229*6dbdd20aSAndroid Build Coastguard Worker   TracedArray AppendArray();
230*6dbdd20aSAndroid Build Coastguard Worker 
231*6dbdd20aSAndroid Build Coastguard Worker  private:
232*6dbdd20aSAndroid Build Coastguard Worker   friend class TracedValue;
233*6dbdd20aSAndroid Build Coastguard Worker 
TracedArray(protos::pbzero::DebugAnnotation * annotation,EventContext * event_context,internal::CheckedScope * parent_scope)234*6dbdd20aSAndroid Build Coastguard Worker   inline TracedArray(protos::pbzero::DebugAnnotation* annotation,
235*6dbdd20aSAndroid Build Coastguard Worker                      EventContext* event_context,
236*6dbdd20aSAndroid Build Coastguard Worker                      internal::CheckedScope* parent_scope)
237*6dbdd20aSAndroid Build Coastguard Worker       : annotation_(annotation),
238*6dbdd20aSAndroid Build Coastguard Worker         event_context_(event_context),
239*6dbdd20aSAndroid Build Coastguard Worker         checked_scope_(parent_scope) {}
240*6dbdd20aSAndroid Build Coastguard Worker 
241*6dbdd20aSAndroid Build Coastguard Worker   protos::pbzero::DebugAnnotation* annotation_;
242*6dbdd20aSAndroid Build Coastguard Worker   EventContext* const event_context_;
243*6dbdd20aSAndroid Build Coastguard Worker 
244*6dbdd20aSAndroid Build Coastguard Worker   internal::CheckedScope checked_scope_;
245*6dbdd20aSAndroid Build Coastguard Worker };
246*6dbdd20aSAndroid Build Coastguard Worker 
247*6dbdd20aSAndroid Build Coastguard Worker class PERFETTO_EXPORT_COMPONENT TracedDictionary {
248*6dbdd20aSAndroid Build Coastguard Worker  public:
249*6dbdd20aSAndroid Build Coastguard Worker   // implicit
250*6dbdd20aSAndroid Build Coastguard Worker   TracedDictionary(TracedValue);
251*6dbdd20aSAndroid Build Coastguard Worker 
252*6dbdd20aSAndroid Build Coastguard Worker   TracedDictionary(const TracedDictionary&) = delete;
253*6dbdd20aSAndroid Build Coastguard Worker   TracedDictionary& operator=(const TracedDictionary&) = delete;
254*6dbdd20aSAndroid Build Coastguard Worker   TracedDictionary& operator=(TracedDictionary&&) = delete;
255*6dbdd20aSAndroid Build Coastguard Worker   TracedDictionary(TracedDictionary&&) = default;
256*6dbdd20aSAndroid Build Coastguard Worker   ~TracedDictionary() = default;
257*6dbdd20aSAndroid Build Coastguard Worker 
258*6dbdd20aSAndroid Build Coastguard Worker   // There are two paths for writing dictionary keys: fast path for writing
259*6dbdd20aSAndroid Build Coastguard Worker   // compile-time const, whose pointer is remains valid during the entire
260*6dbdd20aSAndroid Build Coastguard Worker   // runtime of the program and the slow path for dynamic strings, which need to
261*6dbdd20aSAndroid Build Coastguard Worker   // be copied.
262*6dbdd20aSAndroid Build Coastguard Worker   // In the most common case, a string literal can be passed to `Add`/`AddItem`.
263*6dbdd20aSAndroid Build Coastguard Worker   // In other cases, either StaticString or DynamicString declarations are
264*6dbdd20aSAndroid Build Coastguard Worker   // needed.
265*6dbdd20aSAndroid Build Coastguard Worker 
266*6dbdd20aSAndroid Build Coastguard Worker   TracedValue AddItem(StaticString key);
267*6dbdd20aSAndroid Build Coastguard Worker   TracedValue AddItem(DynamicString key);
268*6dbdd20aSAndroid Build Coastguard Worker 
269*6dbdd20aSAndroid Build Coastguard Worker   template <typename T>
Add(StaticString key,T && value)270*6dbdd20aSAndroid Build Coastguard Worker   void Add(StaticString key, T&& value) {
271*6dbdd20aSAndroid Build Coastguard Worker     WriteIntoTracedValue(AddItem(key), std::forward<T>(value));
272*6dbdd20aSAndroid Build Coastguard Worker   }
273*6dbdd20aSAndroid Build Coastguard Worker 
274*6dbdd20aSAndroid Build Coastguard Worker   template <typename T>
Add(DynamicString key,T && value)275*6dbdd20aSAndroid Build Coastguard Worker   void Add(DynamicString key, T&& value) {
276*6dbdd20aSAndroid Build Coastguard Worker     WriteIntoTracedValue(AddItem(key), std::forward<T>(value));
277*6dbdd20aSAndroid Build Coastguard Worker   }
278*6dbdd20aSAndroid Build Coastguard Worker 
279*6dbdd20aSAndroid Build Coastguard Worker   TracedDictionary AddDictionary(StaticString key);
280*6dbdd20aSAndroid Build Coastguard Worker   TracedDictionary AddDictionary(DynamicString key);
281*6dbdd20aSAndroid Build Coastguard Worker   TracedArray AddArray(StaticString key);
282*6dbdd20aSAndroid Build Coastguard Worker   TracedArray AddArray(DynamicString key);
283*6dbdd20aSAndroid Build Coastguard Worker 
284*6dbdd20aSAndroid Build Coastguard Worker  private:
285*6dbdd20aSAndroid Build Coastguard Worker   friend class TracedValue;
286*6dbdd20aSAndroid Build Coastguard Worker   template <typename T>
287*6dbdd20aSAndroid Build Coastguard Worker   friend class TracedProto;
288*6dbdd20aSAndroid Build Coastguard Worker 
289*6dbdd20aSAndroid Build Coastguard Worker   // Create a |TracedDictionary| which will populate the given field of the
290*6dbdd20aSAndroid Build Coastguard Worker   // given |message|.
291*6dbdd20aSAndroid Build Coastguard Worker   template <typename MessageType, typename FieldMetadata>
TracedDictionary(MessageType * message,FieldMetadata,EventContext * event_context,internal::CheckedScope * parent_scope)292*6dbdd20aSAndroid Build Coastguard Worker   inline TracedDictionary(MessageType* message,
293*6dbdd20aSAndroid Build Coastguard Worker                           FieldMetadata,
294*6dbdd20aSAndroid Build Coastguard Worker                           EventContext* event_context,
295*6dbdd20aSAndroid Build Coastguard Worker                           internal::CheckedScope* parent_scope)
296*6dbdd20aSAndroid Build Coastguard Worker       : message_(message),
297*6dbdd20aSAndroid Build Coastguard Worker         field_id_(FieldMetadata::kFieldId),
298*6dbdd20aSAndroid Build Coastguard Worker         event_context_(event_context),
299*6dbdd20aSAndroid Build Coastguard Worker         checked_scope_(parent_scope) {
300*6dbdd20aSAndroid Build Coastguard Worker     static_assert(std::is_base_of<protozero::Message, MessageType>::value,
301*6dbdd20aSAndroid Build Coastguard Worker                   "Message should be a subclass of protozero::Message");
302*6dbdd20aSAndroid Build Coastguard Worker     static_assert(std::is_base_of<protozero::proto_utils::FieldMetadataBase,
303*6dbdd20aSAndroid Build Coastguard Worker                                   FieldMetadata>::value,
304*6dbdd20aSAndroid Build Coastguard Worker                   "FieldMetadata should be a subclass of FieldMetadataBase");
305*6dbdd20aSAndroid Build Coastguard Worker     static_assert(
306*6dbdd20aSAndroid Build Coastguard Worker         std::is_same<typename FieldMetadata::message_type, MessageType>::value,
307*6dbdd20aSAndroid Build Coastguard Worker         "Field does not belong to this message");
308*6dbdd20aSAndroid Build Coastguard Worker     static_assert(
309*6dbdd20aSAndroid Build Coastguard Worker         std::is_same<typename FieldMetadata::cpp_field_type,
310*6dbdd20aSAndroid Build Coastguard Worker                      ::perfetto::protos::pbzero::DebugAnnotation>::value,
311*6dbdd20aSAndroid Build Coastguard Worker         "Field should be of DebugAnnotation type");
312*6dbdd20aSAndroid Build Coastguard Worker     static_assert(
313*6dbdd20aSAndroid Build Coastguard Worker         FieldMetadata::kRepetitionType ==
314*6dbdd20aSAndroid Build Coastguard Worker             protozero::proto_utils::RepetitionType::kRepeatedNotPacked,
315*6dbdd20aSAndroid Build Coastguard Worker         "Field should be non-packed repeated");
316*6dbdd20aSAndroid Build Coastguard Worker   }
317*6dbdd20aSAndroid Build Coastguard Worker 
318*6dbdd20aSAndroid Build Coastguard Worker   protozero::Message* const message_;
319*6dbdd20aSAndroid Build Coastguard Worker   const uint32_t field_id_;
320*6dbdd20aSAndroid Build Coastguard Worker   EventContext* event_context_;
321*6dbdd20aSAndroid Build Coastguard Worker 
322*6dbdd20aSAndroid Build Coastguard Worker   internal::CheckedScope checked_scope_;
323*6dbdd20aSAndroid Build Coastguard Worker };
324*6dbdd20aSAndroid Build Coastguard Worker 
325*6dbdd20aSAndroid Build Coastguard Worker namespace internal {
326*6dbdd20aSAndroid Build Coastguard Worker 
327*6dbdd20aSAndroid Build Coastguard Worker // SFINAE helpers for finding a right overload to convert a given class to
328*6dbdd20aSAndroid Build Coastguard Worker // trace-friendly form, ordered from most to least preferred.
329*6dbdd20aSAndroid Build Coastguard Worker 
330*6dbdd20aSAndroid Build Coastguard Worker constexpr int kMaxWriteImplPriority = 4;
331*6dbdd20aSAndroid Build Coastguard Worker 
332*6dbdd20aSAndroid Build Coastguard Worker // If T has WriteIntoTracedValue member function, call it.
333*6dbdd20aSAndroid Build Coastguard Worker template <typename T>
334*6dbdd20aSAndroid Build Coastguard Worker decltype(std::declval<T>().WriteIntoTracedValue(std::declval<TracedValue>()),
335*6dbdd20aSAndroid Build Coastguard Worker          void())
WriteImpl(base::priority_tag<4>,TracedValue context,T && value)336*6dbdd20aSAndroid Build Coastguard Worker WriteImpl(base::priority_tag<4>, TracedValue context, T&& value) {
337*6dbdd20aSAndroid Build Coastguard Worker   value.WriteIntoTracedValue(std::move(context));
338*6dbdd20aSAndroid Build Coastguard Worker }
339*6dbdd20aSAndroid Build Coastguard Worker 
340*6dbdd20aSAndroid Build Coastguard Worker // If T has WriteIntoTrace member function, call it.
341*6dbdd20aSAndroid Build Coastguard Worker template <typename T>
342*6dbdd20aSAndroid Build Coastguard Worker decltype(std::declval<T>().WriteIntoTrace(std::declval<TracedValue>()), void())
WriteImpl(base::priority_tag<4>,TracedValue context,T && value)343*6dbdd20aSAndroid Build Coastguard Worker WriteImpl(base::priority_tag<4>, TracedValue context, T&& value) {
344*6dbdd20aSAndroid Build Coastguard Worker   value.WriteIntoTrace(std::move(context));
345*6dbdd20aSAndroid Build Coastguard Worker }
346*6dbdd20aSAndroid Build Coastguard Worker 
347*6dbdd20aSAndroid Build Coastguard Worker // If perfetto::TraceFormatTraits<T>::WriteIntoTracedValue(TracedValue, const
348*6dbdd20aSAndroid Build Coastguard Worker // T&) is available, use it.
349*6dbdd20aSAndroid Build Coastguard Worker template <typename T>
decltype(TraceFormatTraits<base::remove_cvref_t<T>>::WriteIntoTracedValue (std::declval<TracedValue> (),std::declval<T> ()),void ())350*6dbdd20aSAndroid Build Coastguard Worker decltype(TraceFormatTraits<base::remove_cvref_t<T>>::WriteIntoTracedValue(
351*6dbdd20aSAndroid Build Coastguard Worker              std::declval<TracedValue>(),
352*6dbdd20aSAndroid Build Coastguard Worker              std::declval<T>()),
353*6dbdd20aSAndroid Build Coastguard Worker          void())
354*6dbdd20aSAndroid Build Coastguard Worker WriteImpl(base::priority_tag<3>, TracedValue context, T&& value) {
355*6dbdd20aSAndroid Build Coastguard Worker   TraceFormatTraits<base::remove_cvref_t<T>>::WriteIntoTracedValue(
356*6dbdd20aSAndroid Build Coastguard Worker       std::move(context), std::forward<T>(value));
357*6dbdd20aSAndroid Build Coastguard Worker }
358*6dbdd20aSAndroid Build Coastguard Worker 
359*6dbdd20aSAndroid Build Coastguard Worker // If perfetto::TraceFormatTraits<T>::WriteIntoTrace(TracedValue, const T&)
360*6dbdd20aSAndroid Build Coastguard Worker // is available, use it.
361*6dbdd20aSAndroid Build Coastguard Worker template <typename T>
decltype(TraceFormatTraits<base::remove_cvref_t<T>>::WriteIntoTrace (std::declval<TracedValue> (),std::declval<T> ()),void ())362*6dbdd20aSAndroid Build Coastguard Worker decltype(TraceFormatTraits<base::remove_cvref_t<T>>::WriteIntoTrace(
363*6dbdd20aSAndroid Build Coastguard Worker              std::declval<TracedValue>(),
364*6dbdd20aSAndroid Build Coastguard Worker              std::declval<T>()),
365*6dbdd20aSAndroid Build Coastguard Worker          void())
366*6dbdd20aSAndroid Build Coastguard Worker WriteImpl(base::priority_tag<3>, TracedValue context, T&& value) {
367*6dbdd20aSAndroid Build Coastguard Worker   TraceFormatTraits<base::remove_cvref_t<T>>::WriteIntoTrace(
368*6dbdd20aSAndroid Build Coastguard Worker       std::move(context), std::forward<T>(value));
369*6dbdd20aSAndroid Build Coastguard Worker }
370*6dbdd20aSAndroid Build Coastguard Worker 
371*6dbdd20aSAndroid Build Coastguard Worker // If T has operator(), which takes TracedValue, use it.
372*6dbdd20aSAndroid Build Coastguard Worker // Very useful for lambda resolutions.
373*6dbdd20aSAndroid Build Coastguard Worker template <typename T>
decltype(std::declval<T> ()(std::declval<TracedValue> ()),void ())374*6dbdd20aSAndroid Build Coastguard Worker decltype(std::declval<T>()(std::declval<TracedValue>()), void())
375*6dbdd20aSAndroid Build Coastguard Worker WriteImpl(base::priority_tag<2>, TracedValue context, T&& value) {
376*6dbdd20aSAndroid Build Coastguard Worker   std::forward<T>(value)(std::move(context));
377*6dbdd20aSAndroid Build Coastguard Worker }
378*6dbdd20aSAndroid Build Coastguard Worker 
379*6dbdd20aSAndroid Build Coastguard Worker // If T is a container and its elements have tracing support, use it.
380*6dbdd20aSAndroid Build Coastguard Worker //
381*6dbdd20aSAndroid Build Coastguard Worker // Note: a reference to T should be passed to std::begin, otherwise
382*6dbdd20aSAndroid Build Coastguard Worker // for non-reference types const T& will be passed to std::begin, losing
383*6dbdd20aSAndroid Build Coastguard Worker // support for non-const WriteIntoTracedValue methods.
384*6dbdd20aSAndroid Build Coastguard Worker template <typename T>
385*6dbdd20aSAndroid Build Coastguard Worker typename check_traced_value_support<
386*6dbdd20aSAndroid Build Coastguard Worker     decltype(*std::begin(std::declval<T&>()))>::type
WriteImpl(base::priority_tag<1>,TracedValue context,T && value)387*6dbdd20aSAndroid Build Coastguard Worker WriteImpl(base::priority_tag<1>, TracedValue context, T&& value) {
388*6dbdd20aSAndroid Build Coastguard Worker   auto array = std::move(context).WriteArray();
389*6dbdd20aSAndroid Build Coastguard Worker   for (auto&& item : value) {
390*6dbdd20aSAndroid Build Coastguard Worker     array.Append(item);
391*6dbdd20aSAndroid Build Coastguard Worker   }
392*6dbdd20aSAndroid Build Coastguard Worker }
393*6dbdd20aSAndroid Build Coastguard Worker 
394*6dbdd20aSAndroid Build Coastguard Worker // std::underlying_type can't be used with non-enum types, so we need this
395*6dbdd20aSAndroid Build Coastguard Worker // indirection.
396*6dbdd20aSAndroid Build Coastguard Worker template <typename T, bool = std::is_enum<T>::value>
397*6dbdd20aSAndroid Build Coastguard Worker struct safe_underlying_type {
398*6dbdd20aSAndroid Build Coastguard Worker   using type = typename std::underlying_type<T>::type;
399*6dbdd20aSAndroid Build Coastguard Worker };
400*6dbdd20aSAndroid Build Coastguard Worker 
401*6dbdd20aSAndroid Build Coastguard Worker template <typename T>
402*6dbdd20aSAndroid Build Coastguard Worker struct safe_underlying_type<T, false> {
403*6dbdd20aSAndroid Build Coastguard Worker   using type = T;
404*6dbdd20aSAndroid Build Coastguard Worker };
405*6dbdd20aSAndroid Build Coastguard Worker 
406*6dbdd20aSAndroid Build Coastguard Worker template <typename T>
407*6dbdd20aSAndroid Build Coastguard Worker struct is_incomplete_type {
408*6dbdd20aSAndroid Build Coastguard Worker   static constexpr bool value = sizeof(T) != 0;
409*6dbdd20aSAndroid Build Coastguard Worker };
410*6dbdd20aSAndroid Build Coastguard Worker 
411*6dbdd20aSAndroid Build Coastguard Worker // sizeof is not available for const char[], but it's still not considered to be
412*6dbdd20aSAndroid Build Coastguard Worker // an incomplete type for our purposes as the size can be determined at runtime
413*6dbdd20aSAndroid Build Coastguard Worker // due to strings being null-terminated.
414*6dbdd20aSAndroid Build Coastguard Worker template <>
415*6dbdd20aSAndroid Build Coastguard Worker struct is_incomplete_type<const char[]> {
416*6dbdd20aSAndroid Build Coastguard Worker   static constexpr bool value = true;
417*6dbdd20aSAndroid Build Coastguard Worker };
418*6dbdd20aSAndroid Build Coastguard Worker 
419*6dbdd20aSAndroid Build Coastguard Worker }  // namespace internal
420*6dbdd20aSAndroid Build Coastguard Worker 
421*6dbdd20aSAndroid Build Coastguard Worker // Helper template to determine if a given type can be passed to
422*6dbdd20aSAndroid Build Coastguard Worker // perfetto::WriteIntoTracedValue. These templates will fail to resolve if the
423*6dbdd20aSAndroid Build Coastguard Worker // class does not have it support, so they are useful in SFINAE and in producing
424*6dbdd20aSAndroid Build Coastguard Worker // helpful compiler results.
425*6dbdd20aSAndroid Build Coastguard Worker template <typename T, class Result = void>
426*6dbdd20aSAndroid Build Coastguard Worker using check_traced_value_support_t = decltype(
427*6dbdd20aSAndroid Build Coastguard Worker     internal::WriteImpl(
428*6dbdd20aSAndroid Build Coastguard Worker         std::declval<base::priority_tag<internal::kMaxWriteImplPriority>>(),
429*6dbdd20aSAndroid Build Coastguard Worker         std::declval<TracedValue>(),
430*6dbdd20aSAndroid Build Coastguard Worker         std::declval<T>()),
431*6dbdd20aSAndroid Build Coastguard Worker     std::declval<Result>());
432*6dbdd20aSAndroid Build Coastguard Worker 
433*6dbdd20aSAndroid Build Coastguard Worker // check_traced_value_support<T, V>::type is defined (and equal to V) iff T
434*6dbdd20aSAndroid Build Coastguard Worker // supports being passed to WriteIntoTracedValue. See the comment in
435*6dbdd20aSAndroid Build Coastguard Worker // traced_value_forward.h for more details.
436*6dbdd20aSAndroid Build Coastguard Worker template <typename T, class Result>
437*6dbdd20aSAndroid Build Coastguard Worker struct check_traced_value_support<T,
438*6dbdd20aSAndroid Build Coastguard Worker                                   Result,
439*6dbdd20aSAndroid Build Coastguard Worker                                   check_traced_value_support_t<T, Result>> {
440*6dbdd20aSAndroid Build Coastguard Worker   static_assert(
441*6dbdd20aSAndroid Build Coastguard Worker       internal::is_incomplete_type<T>::value,
442*6dbdd20aSAndroid Build Coastguard Worker       "perfetto::TracedValue should not be used with incomplete types");
443*6dbdd20aSAndroid Build Coastguard Worker 
444*6dbdd20aSAndroid Build Coastguard Worker   static constexpr bool value = true;
445*6dbdd20aSAndroid Build Coastguard Worker   using type = Result;
446*6dbdd20aSAndroid Build Coastguard Worker };
447*6dbdd20aSAndroid Build Coastguard Worker 
448*6dbdd20aSAndroid Build Coastguard Worker namespace internal {
449*6dbdd20aSAndroid Build Coastguard Worker 
450*6dbdd20aSAndroid Build Coastguard Worker // Helper class to check if a given type can be passed to
451*6dbdd20aSAndroid Build Coastguard Worker // perfetto::WriteIntoTracedValue. This template will always resolve (with
452*6dbdd20aSAndroid Build Coastguard Worker // |value| being set to either true or false depending on presence of the
453*6dbdd20aSAndroid Build Coastguard Worker // support, so this macro is useful in the situation when you want to e.g. OR
454*6dbdd20aSAndroid Build Coastguard Worker // the result with some other conditions.
455*6dbdd20aSAndroid Build Coastguard Worker //
456*6dbdd20aSAndroid Build Coastguard Worker // In this case, compiler will not give you the full deduction chain, so, for
457*6dbdd20aSAndroid Build Coastguard Worker // example, use check_traced_value_support for writing positive static_asserts
458*6dbdd20aSAndroid Build Coastguard Worker // and has_traced_value_support for writing negative.
459*6dbdd20aSAndroid Build Coastguard Worker template <typename T>
460*6dbdd20aSAndroid Build Coastguard Worker class has_traced_value_support {
461*6dbdd20aSAndroid Build Coastguard Worker   using Yes = char[1];
462*6dbdd20aSAndroid Build Coastguard Worker   using No = char[2];
463*6dbdd20aSAndroid Build Coastguard Worker 
464*6dbdd20aSAndroid Build Coastguard Worker   template <typename V>
465*6dbdd20aSAndroid Build Coastguard Worker   static Yes& check_support(check_traced_value_support_t<V, int>);
466*6dbdd20aSAndroid Build Coastguard Worker   template <typename V>
467*6dbdd20aSAndroid Build Coastguard Worker   static No& check_support(...);
468*6dbdd20aSAndroid Build Coastguard Worker 
469*6dbdd20aSAndroid Build Coastguard Worker  public:
470*6dbdd20aSAndroid Build Coastguard Worker   static constexpr bool value = sizeof(Yes) == sizeof(check_support<T>(0));
471*6dbdd20aSAndroid Build Coastguard Worker };
472*6dbdd20aSAndroid Build Coastguard Worker 
473*6dbdd20aSAndroid Build Coastguard Worker }  // namespace internal
474*6dbdd20aSAndroid Build Coastguard Worker 
475*6dbdd20aSAndroid Build Coastguard Worker template <typename T>
476*6dbdd20aSAndroid Build Coastguard Worker void WriteIntoTracedValue(TracedValue context, T&& value) {
477*6dbdd20aSAndroid Build Coastguard Worker   // TODO(altimin): Add a URL to documentation and a list of common failure
478*6dbdd20aSAndroid Build Coastguard Worker   // patterns.
479*6dbdd20aSAndroid Build Coastguard Worker   static_assert(
480*6dbdd20aSAndroid Build Coastguard Worker       internal::has_traced_value_support<T>::value,
481*6dbdd20aSAndroid Build Coastguard Worker       "The provided type (passed to TRACE_EVENT argument / TracedArray::Append "
482*6dbdd20aSAndroid Build Coastguard Worker       "/ TracedDictionary::Add) does not support being written in a trace "
483*6dbdd20aSAndroid Build Coastguard Worker       "format. Please see the comment in traced_value.h for more details.");
484*6dbdd20aSAndroid Build Coastguard Worker 
485*6dbdd20aSAndroid Build Coastguard Worker   // Should be kept in sync with check_traced_value_support_t!
486*6dbdd20aSAndroid Build Coastguard Worker   internal::WriteImpl(base::priority_tag<internal::kMaxWriteImplPriority>(),
487*6dbdd20aSAndroid Build Coastguard Worker                       std::move(context), std::forward<T>(value));
488*6dbdd20aSAndroid Build Coastguard Worker }
489*6dbdd20aSAndroid Build Coastguard Worker 
490*6dbdd20aSAndroid Build Coastguard Worker // Helpers to write a given value into TracedValue even if the given type
491*6dbdd20aSAndroid Build Coastguard Worker // doesn't support conversion (in which case the provided fallback should be
492*6dbdd20aSAndroid Build Coastguard Worker // used). Useful for automatically generating conversions for autogenerated
493*6dbdd20aSAndroid Build Coastguard Worker // code, but otherwise shouldn't be used as non-autogenerated code is expected
494*6dbdd20aSAndroid Build Coastguard Worker // to define WriteIntoTracedValue convertor.
495*6dbdd20aSAndroid Build Coastguard Worker // See WriteWithFallback test in traced_value_unittest.cc for a concrete
496*6dbdd20aSAndroid Build Coastguard Worker // example.
497*6dbdd20aSAndroid Build Coastguard Worker template <typename T>
498*6dbdd20aSAndroid Build Coastguard Worker typename std::enable_if<internal::has_traced_value_support<T>::value>::type
499*6dbdd20aSAndroid Build Coastguard Worker WriteIntoTracedValueWithFallback(TracedValue context,
500*6dbdd20aSAndroid Build Coastguard Worker                                  T&& value,
501*6dbdd20aSAndroid Build Coastguard Worker                                  const std::string&) {
502*6dbdd20aSAndroid Build Coastguard Worker   WriteIntoTracedValue(std::move(context), std::forward<T>(value));
503*6dbdd20aSAndroid Build Coastguard Worker }
504*6dbdd20aSAndroid Build Coastguard Worker 
505*6dbdd20aSAndroid Build Coastguard Worker template <typename T>
506*6dbdd20aSAndroid Build Coastguard Worker typename std::enable_if<!internal::has_traced_value_support<T>::value>::type
507*6dbdd20aSAndroid Build Coastguard Worker WriteIntoTracedValueWithFallback(TracedValue context,
508*6dbdd20aSAndroid Build Coastguard Worker                                  T&&,
509*6dbdd20aSAndroid Build Coastguard Worker                                  const std::string& fallback) {
510*6dbdd20aSAndroid Build Coastguard Worker   std::move(context).WriteString(fallback);
511*6dbdd20aSAndroid Build Coastguard Worker }
512*6dbdd20aSAndroid Build Coastguard Worker 
513*6dbdd20aSAndroid Build Coastguard Worker // TraceFormatTraits implementations for primitive types.
514*6dbdd20aSAndroid Build Coastguard Worker 
515*6dbdd20aSAndroid Build Coastguard Worker // Specialisation for signed integer types (note: it excludes enums, which have
516*6dbdd20aSAndroid Build Coastguard Worker // their own explicit specialisation).
517*6dbdd20aSAndroid Build Coastguard Worker template <typename T>
518*6dbdd20aSAndroid Build Coastguard Worker struct TraceFormatTraits<
519*6dbdd20aSAndroid Build Coastguard Worker     T,
520*6dbdd20aSAndroid Build Coastguard Worker     typename std::enable_if<std::is_integral<T>::value &&
521*6dbdd20aSAndroid Build Coastguard Worker                             !std::is_same<T, bool>::value &&
522*6dbdd20aSAndroid Build Coastguard Worker                             std::is_signed<T>::value>::type> {
523*6dbdd20aSAndroid Build Coastguard Worker   inline static void WriteIntoTrace(TracedValue context, T value) {
524*6dbdd20aSAndroid Build Coastguard Worker     std::move(context).WriteInt64(value);
525*6dbdd20aSAndroid Build Coastguard Worker   }
526*6dbdd20aSAndroid Build Coastguard Worker };
527*6dbdd20aSAndroid Build Coastguard Worker 
528*6dbdd20aSAndroid Build Coastguard Worker // Specialisation for unsigned integer types (note: it excludes enums, which
529*6dbdd20aSAndroid Build Coastguard Worker // have their own explicit specialisation).
530*6dbdd20aSAndroid Build Coastguard Worker template <typename T>
531*6dbdd20aSAndroid Build Coastguard Worker struct TraceFormatTraits<
532*6dbdd20aSAndroid Build Coastguard Worker     T,
533*6dbdd20aSAndroid Build Coastguard Worker     typename std::enable_if<std::is_integral<T>::value &&
534*6dbdd20aSAndroid Build Coastguard Worker                             !std::is_same<T, bool>::value &&
535*6dbdd20aSAndroid Build Coastguard Worker                             std::is_unsigned<T>::value>::type> {
536*6dbdd20aSAndroid Build Coastguard Worker   inline static void WriteIntoTrace(TracedValue context, T value) {
537*6dbdd20aSAndroid Build Coastguard Worker     std::move(context).WriteUInt64(value);
538*6dbdd20aSAndroid Build Coastguard Worker   }
539*6dbdd20aSAndroid Build Coastguard Worker };
540*6dbdd20aSAndroid Build Coastguard Worker 
541*6dbdd20aSAndroid Build Coastguard Worker // Specialisation for bools.
542*6dbdd20aSAndroid Build Coastguard Worker template <>
543*6dbdd20aSAndroid Build Coastguard Worker struct TraceFormatTraits<bool> {
544*6dbdd20aSAndroid Build Coastguard Worker   inline static void WriteIntoTrace(TracedValue context, bool value) {
545*6dbdd20aSAndroid Build Coastguard Worker     std::move(context).WriteBoolean(value);
546*6dbdd20aSAndroid Build Coastguard Worker   }
547*6dbdd20aSAndroid Build Coastguard Worker };
548*6dbdd20aSAndroid Build Coastguard Worker 
549*6dbdd20aSAndroid Build Coastguard Worker // Specialisation for floating point values.
550*6dbdd20aSAndroid Build Coastguard Worker template <typename T>
551*6dbdd20aSAndroid Build Coastguard Worker struct TraceFormatTraits<
552*6dbdd20aSAndroid Build Coastguard Worker     T,
553*6dbdd20aSAndroid Build Coastguard Worker     typename std::enable_if<std::is_floating_point<T>::value>::type> {
554*6dbdd20aSAndroid Build Coastguard Worker   inline static void WriteIntoTrace(TracedValue context, T value) {
555*6dbdd20aSAndroid Build Coastguard Worker     std::move(context).WriteDouble(static_cast<double>(value));
556*6dbdd20aSAndroid Build Coastguard Worker   }
557*6dbdd20aSAndroid Build Coastguard Worker };
558*6dbdd20aSAndroid Build Coastguard Worker 
559*6dbdd20aSAndroid Build Coastguard Worker // Specialisation for signed enums.
560*6dbdd20aSAndroid Build Coastguard Worker template <typename T>
561*6dbdd20aSAndroid Build Coastguard Worker struct TraceFormatTraits<
562*6dbdd20aSAndroid Build Coastguard Worker     T,
563*6dbdd20aSAndroid Build Coastguard Worker     typename std::enable_if<
564*6dbdd20aSAndroid Build Coastguard Worker         std::is_enum<T>::value &&
565*6dbdd20aSAndroid Build Coastguard Worker         std::is_signed<
566*6dbdd20aSAndroid Build Coastguard Worker             typename internal::safe_underlying_type<T>::type>::value>::type> {
567*6dbdd20aSAndroid Build Coastguard Worker   inline static void WriteIntoTrace(TracedValue context, T value) {
568*6dbdd20aSAndroid Build Coastguard Worker     std::move(context).WriteInt64(static_cast<int64_t>(value));
569*6dbdd20aSAndroid Build Coastguard Worker   }
570*6dbdd20aSAndroid Build Coastguard Worker };
571*6dbdd20aSAndroid Build Coastguard Worker 
572*6dbdd20aSAndroid Build Coastguard Worker // Specialisation for unsigned enums.
573*6dbdd20aSAndroid Build Coastguard Worker template <typename T>
574*6dbdd20aSAndroid Build Coastguard Worker struct TraceFormatTraits<
575*6dbdd20aSAndroid Build Coastguard Worker     T,
576*6dbdd20aSAndroid Build Coastguard Worker     typename std::enable_if<
577*6dbdd20aSAndroid Build Coastguard Worker         std::is_enum<T>::value &&
578*6dbdd20aSAndroid Build Coastguard Worker         std::is_unsigned<
579*6dbdd20aSAndroid Build Coastguard Worker             typename internal::safe_underlying_type<T>::type>::value>::type> {
580*6dbdd20aSAndroid Build Coastguard Worker   inline static void WriteIntoTrace(TracedValue context, T value) {
581*6dbdd20aSAndroid Build Coastguard Worker     std::move(context).WriteUInt64(static_cast<uint64_t>(value));
582*6dbdd20aSAndroid Build Coastguard Worker   }
583*6dbdd20aSAndroid Build Coastguard Worker };
584*6dbdd20aSAndroid Build Coastguard Worker 
585*6dbdd20aSAndroid Build Coastguard Worker // Specialisations for C-style strings.
586*6dbdd20aSAndroid Build Coastguard Worker template <>
587*6dbdd20aSAndroid Build Coastguard Worker struct TraceFormatTraits<const char*> {
588*6dbdd20aSAndroid Build Coastguard Worker   inline static void WriteIntoTrace(TracedValue context, const char* value) {
589*6dbdd20aSAndroid Build Coastguard Worker     std::move(context).WriteString(value);
590*6dbdd20aSAndroid Build Coastguard Worker   }
591*6dbdd20aSAndroid Build Coastguard Worker };
592*6dbdd20aSAndroid Build Coastguard Worker 
593*6dbdd20aSAndroid Build Coastguard Worker template <>
594*6dbdd20aSAndroid Build Coastguard Worker struct TraceFormatTraits<char[]> {
595*6dbdd20aSAndroid Build Coastguard Worker   inline static void WriteIntoTrace(TracedValue context, const char value[]) {
596*6dbdd20aSAndroid Build Coastguard Worker     std::move(context).WriteString(value);
597*6dbdd20aSAndroid Build Coastguard Worker   }
598*6dbdd20aSAndroid Build Coastguard Worker };
599*6dbdd20aSAndroid Build Coastguard Worker 
600*6dbdd20aSAndroid Build Coastguard Worker template <size_t N>
601*6dbdd20aSAndroid Build Coastguard Worker struct TraceFormatTraits<char[N]> {
602*6dbdd20aSAndroid Build Coastguard Worker   inline static void WriteIntoTrace(TracedValue context, const char value[N]) {
603*6dbdd20aSAndroid Build Coastguard Worker     std::move(context).WriteString(value);
604*6dbdd20aSAndroid Build Coastguard Worker   }
605*6dbdd20aSAndroid Build Coastguard Worker };
606*6dbdd20aSAndroid Build Coastguard Worker 
607*6dbdd20aSAndroid Build Coastguard Worker // Specialization for Perfetto strings.
608*6dbdd20aSAndroid Build Coastguard Worker template <>
609*6dbdd20aSAndroid Build Coastguard Worker struct TraceFormatTraits<perfetto::StaticString> {
610*6dbdd20aSAndroid Build Coastguard Worker   inline static void WriteIntoTrace(TracedValue context,
611*6dbdd20aSAndroid Build Coastguard Worker                                     perfetto::StaticString str) {
612*6dbdd20aSAndroid Build Coastguard Worker     std::move(context).WriteString(str.value);
613*6dbdd20aSAndroid Build Coastguard Worker   }
614*6dbdd20aSAndroid Build Coastguard Worker };
615*6dbdd20aSAndroid Build Coastguard Worker 
616*6dbdd20aSAndroid Build Coastguard Worker template <>
617*6dbdd20aSAndroid Build Coastguard Worker struct TraceFormatTraits<perfetto::DynamicString> {
618*6dbdd20aSAndroid Build Coastguard Worker   inline static void WriteIntoTrace(TracedValue context,
619*6dbdd20aSAndroid Build Coastguard Worker                                     perfetto::DynamicString str) {
620*6dbdd20aSAndroid Build Coastguard Worker     std::move(context).WriteString(str.value, str.length);
621*6dbdd20aSAndroid Build Coastguard Worker   }
622*6dbdd20aSAndroid Build Coastguard Worker };
623*6dbdd20aSAndroid Build Coastguard Worker 
624*6dbdd20aSAndroid Build Coastguard Worker // Specialisation for C++ strings.
625*6dbdd20aSAndroid Build Coastguard Worker template <>
626*6dbdd20aSAndroid Build Coastguard Worker struct TraceFormatTraits<std::string> {
627*6dbdd20aSAndroid Build Coastguard Worker   inline static void WriteIntoTrace(TracedValue context,
628*6dbdd20aSAndroid Build Coastguard Worker                                     const std::string& value) {
629*6dbdd20aSAndroid Build Coastguard Worker     std::move(context).WriteString(value);
630*6dbdd20aSAndroid Build Coastguard Worker   }
631*6dbdd20aSAndroid Build Coastguard Worker };
632*6dbdd20aSAndroid Build Coastguard Worker 
633*6dbdd20aSAndroid Build Coastguard Worker // Specialisation for C++ string_views.
634*6dbdd20aSAndroid Build Coastguard Worker template <>
635*6dbdd20aSAndroid Build Coastguard Worker struct TraceFormatTraits<std::string_view> {
636*6dbdd20aSAndroid Build Coastguard Worker   inline static void WriteIntoTrace(TracedValue context,
637*6dbdd20aSAndroid Build Coastguard Worker                                     std::string_view value) {
638*6dbdd20aSAndroid Build Coastguard Worker     std::move(context).WriteString(value);
639*6dbdd20aSAndroid Build Coastguard Worker   }
640*6dbdd20aSAndroid Build Coastguard Worker };
641*6dbdd20aSAndroid Build Coastguard Worker 
642*6dbdd20aSAndroid Build Coastguard Worker // Specialisation for (const) void*, which writes the pointer value.
643*6dbdd20aSAndroid Build Coastguard Worker template <>
644*6dbdd20aSAndroid Build Coastguard Worker struct TraceFormatTraits<void*> {
645*6dbdd20aSAndroid Build Coastguard Worker   inline static void WriteIntoTrace(TracedValue context, void* value) {
646*6dbdd20aSAndroid Build Coastguard Worker     std::move(context).WritePointer(value);
647*6dbdd20aSAndroid Build Coastguard Worker   }
648*6dbdd20aSAndroid Build Coastguard Worker };
649*6dbdd20aSAndroid Build Coastguard Worker 
650*6dbdd20aSAndroid Build Coastguard Worker template <>
651*6dbdd20aSAndroid Build Coastguard Worker struct TraceFormatTraits<const void*> {
652*6dbdd20aSAndroid Build Coastguard Worker   inline static void WriteIntoTrace(TracedValue context, const void* value) {
653*6dbdd20aSAndroid Build Coastguard Worker     std::move(context).WritePointer(value);
654*6dbdd20aSAndroid Build Coastguard Worker   }
655*6dbdd20aSAndroid Build Coastguard Worker };
656*6dbdd20aSAndroid Build Coastguard Worker 
657*6dbdd20aSAndroid Build Coastguard Worker // Specialisation for std::unique_ptr<>, which writes either nullptr or the
658*6dbdd20aSAndroid Build Coastguard Worker // object it points to.
659*6dbdd20aSAndroid Build Coastguard Worker template <typename T>
660*6dbdd20aSAndroid Build Coastguard Worker struct TraceFormatTraits<std::unique_ptr<T>, check_traced_value_support_t<T>> {
661*6dbdd20aSAndroid Build Coastguard Worker   inline static void WriteIntoTrace(TracedValue context,
662*6dbdd20aSAndroid Build Coastguard Worker                                     const std::unique_ptr<T>& value) {
663*6dbdd20aSAndroid Build Coastguard Worker     ::perfetto::WriteIntoTracedValue(std::move(context), value.get());
664*6dbdd20aSAndroid Build Coastguard Worker   }
665*6dbdd20aSAndroid Build Coastguard Worker 
666*6dbdd20aSAndroid Build Coastguard Worker   template <typename MessageType>
667*6dbdd20aSAndroid Build Coastguard Worker   inline static void WriteIntoTrace(TracedProto<MessageType> message,
668*6dbdd20aSAndroid Build Coastguard Worker                                     const std::unique_ptr<T>& value) {
669*6dbdd20aSAndroid Build Coastguard Worker     ::perfetto::WriteIntoTracedProto(std::move(message), value.get());
670*6dbdd20aSAndroid Build Coastguard Worker   }
671*6dbdd20aSAndroid Build Coastguard Worker };
672*6dbdd20aSAndroid Build Coastguard Worker 
673*6dbdd20aSAndroid Build Coastguard Worker // Specialisation for raw pointer, which writes either nullptr or the object it
674*6dbdd20aSAndroid Build Coastguard Worker // points to.
675*6dbdd20aSAndroid Build Coastguard Worker template <typename T>
676*6dbdd20aSAndroid Build Coastguard Worker struct TraceFormatTraits<T*, check_traced_value_support_t<T>> {
677*6dbdd20aSAndroid Build Coastguard Worker   inline static void WriteIntoTrace(TracedValue context, T* value) {
678*6dbdd20aSAndroid Build Coastguard Worker     if (!value) {
679*6dbdd20aSAndroid Build Coastguard Worker       std::move(context).WritePointer(nullptr);
680*6dbdd20aSAndroid Build Coastguard Worker       return;
681*6dbdd20aSAndroid Build Coastguard Worker     }
682*6dbdd20aSAndroid Build Coastguard Worker     ::perfetto::WriteIntoTracedValue(std::move(context), *value);
683*6dbdd20aSAndroid Build Coastguard Worker   }
684*6dbdd20aSAndroid Build Coastguard Worker 
685*6dbdd20aSAndroid Build Coastguard Worker   template <typename MessageType>
686*6dbdd20aSAndroid Build Coastguard Worker   inline static void WriteIntoTrace(TracedProto<MessageType> message,
687*6dbdd20aSAndroid Build Coastguard Worker                                     T* value) {
688*6dbdd20aSAndroid Build Coastguard Worker     if (!value) {
689*6dbdd20aSAndroid Build Coastguard Worker       // Start the message, but do not write anything. TraceProcessor will emit
690*6dbdd20aSAndroid Build Coastguard Worker       // a NULL value.
691*6dbdd20aSAndroid Build Coastguard Worker       return;
692*6dbdd20aSAndroid Build Coastguard Worker     }
693*6dbdd20aSAndroid Build Coastguard Worker 
694*6dbdd20aSAndroid Build Coastguard Worker     ::perfetto::WriteIntoTracedProto(std::move(message), *value);
695*6dbdd20aSAndroid Build Coastguard Worker   }
696*6dbdd20aSAndroid Build Coastguard Worker };
697*6dbdd20aSAndroid Build Coastguard Worker 
698*6dbdd20aSAndroid Build Coastguard Worker // Specialisation for nullptr.
699*6dbdd20aSAndroid Build Coastguard Worker template <>
700*6dbdd20aSAndroid Build Coastguard Worker struct TraceFormatTraits<std::nullptr_t> {
701*6dbdd20aSAndroid Build Coastguard Worker   inline static void WriteIntoTrace(TracedValue context, std::nullptr_t) {
702*6dbdd20aSAndroid Build Coastguard Worker     std::move(context).WritePointer(nullptr);
703*6dbdd20aSAndroid Build Coastguard Worker   }
704*6dbdd20aSAndroid Build Coastguard Worker 
705*6dbdd20aSAndroid Build Coastguard Worker   template <typename MessageType>
706*6dbdd20aSAndroid Build Coastguard Worker   inline static void WriteIntoTrace(TracedProto<MessageType>, std::nullptr_t) {
707*6dbdd20aSAndroid Build Coastguard Worker     // Start the message, but do not write anything. TraceProcessor will emit a
708*6dbdd20aSAndroid Build Coastguard Worker     // NULL value.
709*6dbdd20aSAndroid Build Coastguard Worker   }
710*6dbdd20aSAndroid Build Coastguard Worker };
711*6dbdd20aSAndroid Build Coastguard Worker 
712*6dbdd20aSAndroid Build Coastguard Worker }  // namespace perfetto
713*6dbdd20aSAndroid Build Coastguard Worker 
714*6dbdd20aSAndroid Build Coastguard Worker #endif  // INCLUDE_PERFETTO_TRACING_TRACED_VALUE_H_
715