trace_conversion_helper.h 9.1 KB

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