• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 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_TRACE_CONVERSION_HELPER_H_
6 #define BASE_TRACE_EVENT_TRACE_CONVERSION_HELPER_H_
7 
8 #include <sstream>
9 #include <string>
10 
11 #include "base/strings/string_number_conversions.h"
12 #include "base/template_util.h"
13 #include "base/trace_event/traced_value.h"
14 
15 namespace base {
16 
17 namespace trace_event {
18 
19 // Helpers for base::trace_event::ValueToString.
20 namespace internal {
21 
22 // Return std::string representation given by |value|'s ostream operator<<.
23 template <typename ValueType>
OstreamValueToString(const ValueType & value)24 std::string OstreamValueToString(const ValueType& value) {
25   std::stringstream ss;
26   ss << value;
27   return ss.str();
28 }
29 
30 // Use SFINAE to decide how to extract a string from the given parameter.
31 
32 // Check if |value| can be used as a parameter of |base::NumberToString|. If
33 // std::string is not constructible from the returned value of
34 // |base::NumberToString| cause compilation error.
35 //
36 // |base::NumberToString| does not do locale specific formatting and should be
37 // faster than using |std::ostream::operator<<|.
38 template <typename ValueType>
decltype(base::NumberToString (std::declval<const ValueType> ()),std::string ())39 decltype(base::NumberToString(std::declval<const ValueType>()), std::string())
40 ValueToStringHelper(base::internal::priority_tag<5>,
41                     const ValueType& value,
42                     std::string /* unused */) {
43   return base::NumberToString(value);
44 }
45 
46 // If there is |ValueType::ToString| whose return value can be used to construct
47 // |std::string|, use this. Else use other methods.
48 template <typename ValueType>
49 decltype(std::string(std::declval<const ValueType>().ToString()))
ValueToStringHelper(base::internal::priority_tag<4>,const ValueType & value,std::string)50 ValueToStringHelper(base::internal::priority_tag<4>,
51                     const ValueType& value,
52                     std::string /* unused */) {
53   return value.ToString();
54 }
55 
56 // If |std::ostream::operator<<| can be used, use it. Useful for |void*|.
57 template <typename ValueType>
58 decltype(
59     std::declval<std::ostream>().operator<<(std::declval<const ValueType>()),
60     std::string())
ValueToStringHelper(base::internal::priority_tag<3>,const ValueType & value,std::string)61 ValueToStringHelper(base::internal::priority_tag<3>,
62                     const ValueType& value,
63                     std::string /* unused */) {
64   return OstreamValueToString(value);
65 }
66 
67 // Use |ValueType::operator<<| if applicable.
68 template <typename ValueType>
69 decltype(operator<<(std::declval<std::ostream&>(),
70                     std::declval<const ValueType&>()),
71          std::string())
ValueToStringHelper(base::internal::priority_tag<2>,const ValueType & value,std::string)72 ValueToStringHelper(base::internal::priority_tag<2>,
73                     const ValueType& value,
74                     std::string /* unused */) {
75   return OstreamValueToString(value);
76 }
77 
78 // If there is |ValueType::data| whose return value can be used to construct
79 // |std::string|, use it.
80 template <typename ValueType>
81 decltype(std::string(std::declval<const ValueType>().data()))
ValueToStringHelper(base::internal::priority_tag<1>,const ValueType & value,std::string)82 ValueToStringHelper(base::internal::priority_tag<1>,
83                     const ValueType& value,
84                     std::string /* unused */) {
85   return value.data();
86 }
87 
88 // Fallback returns the |fallback_value|. Needs to have |ValueToStringPriority|
89 // with the highest number (to be called last).
90 template <typename ValueType>
ValueToStringHelper(base::internal::priority_tag<0>,const ValueType &,std::string fallback_value)91 std::string ValueToStringHelper(base::internal::priority_tag<0>,
92                                 const ValueType& /* unused */,
93                                 std::string fallback_value) {
94   return fallback_value;
95 }
96 
97 /*********************************************
98 ********* SetTracedValueArg methods. *********
99 *********************************************/
100 
101 // base::internal::priority_tag parameter is there to define ordering in which
102 // the following methods will be considered. Note that for instance |bool| type
103 // is also |std::is_integral|, so we need to test |bool| before testing for
104 // integral.
105 template <typename T>
106 typename std::enable_if<std::is_same<T, bool>::value>::type
SetTracedValueArgHelper(base::internal::priority_tag<6>,TracedValue * traced_value,const char * name,const T & value)107 SetTracedValueArgHelper(base::internal::priority_tag<6>,
108                         TracedValue* traced_value,
109                         const char* name,
110                         const T& value) {
111   traced_value->SetBoolean(name, value);
112 }
113 
114 // std::is_integral<bool>::value == true
115 // This needs to be considered only when T is not bool (has higher
116 // base::internal::priority_tag).
117 template <typename T>
118 typename std::enable_if<std::is_integral<T>::value>::type
SetTracedValueArgHelper(base::internal::priority_tag<5>,TracedValue * traced_value,const char * name,const T & value)119 SetTracedValueArgHelper(base::internal::priority_tag<5>,
120                         TracedValue* traced_value,
121                         const char* name,
122                         const T& value) {
123   // Avoid loss of precision.
124   if (sizeof(int) < sizeof(value)) {
125     // TODO(crbug.com/1111787): Add 64-bit support to TracedValue.
126     traced_value->SetString(name, base::NumberToString(value));
127   } else {
128     traced_value->SetInteger(name, value);
129   }
130 }
131 
132 // Any floating point type is converted to double.
133 template <typename T>
134 typename std::enable_if<std::is_floating_point<T>::value>::type
SetTracedValueArgHelper(base::internal::priority_tag<4>,TracedValue * traced_value,const char * name,const T & value)135 SetTracedValueArgHelper(base::internal::priority_tag<4>,
136                         TracedValue* traced_value,
137                         const char* name,
138                         const T& value) {
139   traced_value->SetDouble(name, static_cast<double>(value));
140 }
141 
142 // |void*| is traced natively.
143 template <typename T>
144 typename std::enable_if<std::is_same<T, void*>::value>::type
SetTracedValueArgHelper(base::internal::priority_tag<3>,TracedValue * traced_value,const char * name,const T & value)145 SetTracedValueArgHelper(base::internal::priority_tag<3>,
146                         TracedValue* traced_value,
147                         const char* name,
148                         const T& value) {
149   traced_value->SetPointer(name, value);
150 }
151 
152 // |const char*| is traced natively.
153 template <typename T>
154 typename std::enable_if<std::is_same<T, const char*>::value>::type
SetTracedValueArgHelper(base::internal::priority_tag<2>,TracedValue * traced_value,const char * name,const T & value)155 SetTracedValueArgHelper(base::internal::priority_tag<2>,
156                         TracedValue* traced_value,
157                         const char* name,
158                         const T& value) {
159   traced_value->SetString(name, value);
160 }
161 
162 // If an instance of |base::StringPiece| can be constructed from an instance of
163 // |T| trace |value| as a string.
164 template <typename T>
decltype(base::StringPiece (std::declval<const T> ()),void ())165 decltype(base::StringPiece(std::declval<const T>()), void())
166 SetTracedValueArgHelper(base::internal::priority_tag<1>,
167                         TracedValue* traced_value,
168                         const char* name,
169                         const T& value) {
170   traced_value->SetString(name, value);
171 }
172 
173 // Fallback.
174 template <typename T>
SetTracedValueArgHelper(base::internal::priority_tag<0>,TracedValue * traced_value,const char * name,const T &)175 void SetTracedValueArgHelper(base::internal::priority_tag<0>,
176                              TracedValue* traced_value,
177                              const char* name,
178                              const T& /* unused */) {
179   // TODO(crbug.com/1111787): Add fallback to |ValueToString|. Crashes on
180   // operator<< have been seen with it.
181   traced_value->SetString(name, "<value>");
182 }
183 
184 }  // namespace internal
185 
186 // The function to be used.
187 template <typename ValueType>
188 std::string ValueToString(const ValueType& value,
189                           std::string fallback_value = "<value>") {
190   return internal::ValueToStringHelper(base::internal::priority_tag<5>(), value,
191                                        std::move(fallback_value));
192 }
193 
194 // Method to trace |value| into the given |traced_value|. Support types where
195 // there is |TracedValue::SetT| natively.
196 //
197 // TODO(crbug.com/1111787): Add support for:
198 //   absl::optional
199 //   AsValueInto (T& and T*)
200 //   array and map types
201 //   fallback to ValueToString
202 template <typename ValueType>
SetTracedValueArg(TracedValue * traced_value,const char * name,const ValueType & value)203 void SetTracedValueArg(TracedValue* traced_value,
204                        const char* name,
205                        const ValueType& value) {
206   internal::SetTracedValueArgHelper(base::internal::priority_tag<6>(),
207                                     traced_value, name, value);
208 }
209 
210 // Parameter pack support: do nothing for an empty parameter pack.
211 //
212 // Inline this to avoid linker duplicate symbol error.
SetTracedValueArg(TracedValue * traced_value,const char * name)213 inline void SetTracedValueArg(TracedValue* traced_value, const char* name) {}
214 
215 // Parameter pack support. All of the packed parameters are traced under the
216 // same name. Serves to trace a parameter pack, all parameters having the same
217 // name (of the parameter pack) is desired.
218 //
219 // Example use when |args| is a parameter pack:
220 //   SetTracedValueArg(traced_value, name, args...);
221 template <typename ValueType, typename... ValueTypes>
SetTracedValueArg(TracedValue * traced_value,const char * name,const ValueType & value,const ValueTypes &...args)222 void SetTracedValueArg(TracedValue* traced_value,
223                        const char* name,
224                        const ValueType& value,
225                        const ValueTypes&... args) {
226   SetTracedValueArg(traced_value, name, value);
227   // Trace the rest from the parameter pack.
228   SetTracedValueArg(traced_value, name, args...);
229 }
230 
231 }  // namespace trace_event
232 }  // namespace base
233 
234 #endif  // BASE_TRACE_EVENT_TRACE_CONVERSION_HELPER_H_
235