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