• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 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_STRINGS_TO_STRING_H_
6 #define BASE_STRINGS_TO_STRING_H_
7 
8 #include <ios>
9 #include <memory>
10 #include <sstream>
11 #include <string>
12 #include <type_traits>
13 
14 #include "base/template_util.h"
15 #include "base/types/supports_ostream_operator.h"
16 
17 namespace base {
18 
19 namespace internal {
20 
21 // I/O manipulators are function pointers, but should be sent directly to the
22 // `ostream` instead of being cast to `const void*` like other function
23 // pointers.
24 template <typename T, typename = void>
25 constexpr bool IsIomanip = false;
26 template <typename T>
27 constexpr bool
28     IsIomanip<T&(T&), std::enable_if_t<std::is_base_of_v<std::ios_base, T>>> =
29         true;
30 
31 // Function pointers implicitly convert to `bool`, so use this to avoid printing
32 // function pointers as 1 or 0.
33 template <typename T, typename = void>
34 constexpr bool WillBeIncorrectlyStreamedAsBool = false;
35 template <typename T>
36 constexpr bool WillBeIncorrectlyStreamedAsBool<
37     T,
38     std::enable_if_t<std::is_function_v<std::remove_pointer_t<T>> &&
39                      !IsIomanip<std::remove_pointer_t<T>>>> = true;
40 
41 // Fallback case when there is no better representation.
42 template <typename T, typename = void>
43 struct ToStringHelper {
StringifyToStringHelper44   static void Stringify(const T& v, std::ostringstream& ss) {
45     ss << "[" << sizeof(v) << "-byte object at 0x" << std::addressof(v) << "]";
46   }
47 };
48 
49 // Most streamables.
50 template <typename T>
51 struct ToStringHelper<
52     T,
53     std::enable_if_t<SupportsOstreamOperator<const T&>::value &&
54                      !WillBeIncorrectlyStreamedAsBool<T>>> {
55   static void Stringify(const T& v, std::ostringstream& ss) { ss << v; }
56 };
57 
58 // Functions and function pointers.
59 template <typename T>
60 struct ToStringHelper<
61     T,
62     std::enable_if_t<SupportsOstreamOperator<const T&>::value &&
63                      WillBeIncorrectlyStreamedAsBool<T>>> {
64   static void Stringify(const T& v, std::ostringstream& ss) {
65     ToStringHelper<const void*>::Stringify(reinterpret_cast<const void*>(v),
66                                            ss);
67   }
68 };
69 
70 // Non-streamables that have a `ToString` member.
71 template <typename T>
72 struct ToStringHelper<
73     T,
74     std::enable_if_t<!SupportsOstreamOperator<const T&>::value &&
75                      SupportsToString<const T&>::value>> {
76   static void Stringify(const T& v, std::ostringstream& ss) {
77     // .ToString() may not return a std::string, e.g. blink::WTF::String.
78     ToStringHelper<decltype(v.ToString())>::Stringify(v.ToString(), ss);
79   }
80 };
81 
82 // Non-streamable enums (i.e. scoped enums where no `operator<<` overload was
83 // declared).
84 template <typename T>
85 struct ToStringHelper<
86     T,
87     std::enable_if_t<!SupportsOstreamOperator<const T&>::value &&
88                      std::is_enum_v<T>>> {
89   static void Stringify(const T& v, std::ostringstream& ss) {
90     using UT = typename std::underlying_type_t<T>;
91     ToStringHelper<UT>::Stringify(static_cast<UT>(v), ss);
92   }
93 };
94 
95 }  // namespace internal
96 
97 // Converts any type to a string, preferring defined operator<<() or ToString()
98 // methods if they exist.
99 template <typename... Ts>
100 std::string ToString(const Ts&... values) {
101   std::ostringstream ss;
102   (internal::ToStringHelper<remove_cvref_t<decltype(values)>>::Stringify(values,
103                                                                          ss),
104    ...);
105   return ss.str();
106 }
107 
108 }  // namespace base
109 
110 #endif  // BASE_STRINGS_TO_STRING_H_
111