xref: /aosp_15_r20/external/pytorch/c10/util/StringUtil.h (revision da0073e96a02ea20f0ac840b70461e3646d07c45)
1 #ifndef C10_UTIL_STRINGUTIL_H_
2 #define C10_UTIL_STRINGUTIL_H_
3 
4 #include <c10/macros/Macros.h>
5 #include <c10/util/string_utils.h>
6 #include <c10/util/string_view.h>
7 
8 #include <cstddef>
9 #include <ostream>
10 #include <sstream>
11 #include <string>
12 
13 C10_CLANG_DIAGNOSTIC_PUSH()
14 #if C10_CLANG_HAS_WARNING("-Wshorten-64-to-32")
15 C10_CLANG_DIAGNOSTIC_IGNORE("-Wshorten-64-to-32")
16 #endif
17 
18 namespace c10 {
19 
20 namespace detail {
21 
22 // Obtains the base name from a full path.
23 C10_API std::string StripBasename(const std::string& full_path);
24 
25 C10_API std::string ExcludeFileExtension(const std::string& full_path);
26 
27 struct CompileTimeEmptyString {
28   operator const std::string&() const {
29     static const std::string empty_string_literal;
30     return empty_string_literal;
31   }
32   operator const char*() const {
33     return "";
34   }
35 };
36 
37 template <typename T>
38 struct CanonicalizeStrTypes {
39   using type = const T&;
40 };
41 
42 template <size_t N>
43 // NOLINTNEXTLINE(*c-arrays*)
44 struct CanonicalizeStrTypes<char[N]> {
45   using type = const char*;
46 };
47 
48 inline std::ostream& _str(std::ostream& ss) {
49   return ss;
50 }
51 
52 template <typename T>
53 inline std::ostream& _str(std::ostream& ss, const T& t) {
54   // NOLINTNEXTLINE(clang-analyzer-core.CallAndMessage)
55   ss << t;
56   return ss;
57 }
58 
59 // Overloads of _str for wide types; forces narrowing.
60 C10_API std::ostream& _str(std::ostream& ss, const wchar_t* wCStr);
61 C10_API std::ostream& _str(std::ostream& ss, const wchar_t& wChar);
62 C10_API std::ostream& _str(std::ostream& ss, const std::wstring& wString);
63 
64 template <>
65 inline std::ostream& _str<CompileTimeEmptyString>(
66     std::ostream& ss,
67     const CompileTimeEmptyString&) {
68   return ss;
69 }
70 
71 template <typename T, typename... Args>
72 inline std::ostream& _str(std::ostream& ss, const T& t, const Args&... args) {
73   return _str(_str(ss, t), args...);
74 }
75 
76 template <typename... Args>
77 struct _str_wrapper final {
78   static std::string call(const Args&... args) {
79     std::ostringstream ss;
80     _str(ss, args...);
81     return ss.str();
82   }
83 };
84 
85 // Specializations for already-a-string types.
86 template <>
87 struct _str_wrapper<std::string> final {
88   // return by reference to avoid the binary size of a string copy
89   static const std::string& call(const std::string& str) {
90     return str;
91   }
92 };
93 
94 template <>
95 struct _str_wrapper<const char*> final {
96   static const char* call(const char* str) {
97     return str;
98   }
99 };
100 
101 // For c10::str() with an empty argument list (which is common in our assert
102 // macros), we don't want to pay the binary size for constructing and
103 // destructing a stringstream or even constructing a string.
104 template <>
105 struct _str_wrapper<> final {
106   static CompileTimeEmptyString call() {
107     return CompileTimeEmptyString();
108   }
109 };
110 
111 } // namespace detail
112 
113 // Convert a list of string-like arguments into a single string.
114 template <typename... Args>
115 inline decltype(auto) str(const Args&... args) {
116   return detail::_str_wrapper<
117       typename detail::CanonicalizeStrTypes<Args>::type...>::call(args...);
118 }
119 
120 template <class Container>
121 inline std::string Join(const std::string& delimiter, const Container& v) {
122   std::stringstream s;
123   int cnt = static_cast<int64_t>(v.size()) - 1;
124   for (auto i = v.begin(); i != v.end(); ++i, --cnt) {
125     s << (*i) << (cnt ? delimiter : "");
126   }
127   return s.str();
128 }
129 
130 // Replace all occurrences of "from" substring to "to" string.
131 // Returns number of replacements
132 size_t C10_API
133 ReplaceAll(std::string& s, c10::string_view from, c10::string_view to);
134 
135 /// Represents a location in source code (for debugging).
136 struct C10_API SourceLocation {
137   const char* function;
138   const char* file;
139   uint32_t line;
140 };
141 
142 std::ostream& operator<<(std::ostream& out, const SourceLocation& loc);
143 
144 // unix isprint but insensitive to locale
145 inline bool isPrint(char s) {
146   return s > 0x1f && s < 0x7f;
147 }
148 
149 inline void printQuotedString(std::ostream& stmt, const string_view str) {
150   stmt << "\"";
151   for (auto s : str) {
152     switch (s) {
153       case '\\':
154         stmt << "\\\\";
155         break;
156       case '\'':
157         stmt << "\\'";
158         break;
159       case '\"':
160         stmt << "\\\"";
161         break;
162       case '\a':
163         stmt << "\\a";
164         break;
165       case '\b':
166         stmt << "\\b";
167         break;
168       case '\f':
169         stmt << "\\f";
170         break;
171       case '\n':
172         stmt << "\\n";
173         break;
174       case '\r':
175         stmt << "\\r";
176         break;
177       case '\t':
178         stmt << "\\t";
179         break;
180       case '\v':
181         stmt << "\\v";
182         break;
183       default:
184         if (isPrint(s)) {
185           stmt << s;
186         } else {
187           // C++ io has stateful formatting settings. Messing with
188           // them is probably worse than doing this manually.
189           // NOLINTNEXTLINE(*c-arrays*)
190           char buf[4] = "000";
191           // NOLINTNEXTLINE(*narrowing-conversions)
192           buf[2] += s % 8;
193           s /= 8;
194           // NOLINTNEXTLINE(*narrowing-conversions)
195           buf[1] += s % 8;
196           s /= 8;
197           // NOLINTNEXTLINE(*narrowing-conversions)
198           buf[0] += s;
199           stmt << "\\" << buf;
200         }
201         break;
202     }
203   }
204   stmt << "\"";
205 }
206 
207 } // namespace c10
208 
209 C10_CLANG_DIAGNOSTIC_POP()
210 
211 #endif // C10_UTIL_STRINGUTIL_H_
212