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 | |
14 | C10_CLANG_DIAGNOSTIC_PUSH() |
15 | #if C10_CLANG_HAS_WARNING("-Wshorten-64-to-32") |
16 | C10_CLANG_DIAGNOSTIC_IGNORE("-Wshorten-64-to-32" ) |
17 | #endif |
18 | |
19 | namespace c10 { |
20 | |
21 | namespace detail { |
22 | |
23 | // Obtains the base name from a full path. |
24 | C10_API std::string StripBasename(const std::string& full_path); |
25 | |
26 | C10_API std::string ExcludeFileExtension(const std::string& full_path); |
27 | |
28 | struct 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 | |
38 | template <typename T> |
39 | struct CanonicalizeStrTypes { |
40 | using type = const T&; |
41 | }; |
42 | |
43 | template <size_t N> |
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 | template <> |
60 | inline std::ostream& _str<CompileTimeEmptyString>( |
61 | std::ostream& ss, |
62 | const CompileTimeEmptyString&) { |
63 | return ss; |
64 | } |
65 | |
66 | template <typename T, typename... Args> |
67 | inline std::ostream& _str(std::ostream& ss, const T& t, const Args&... args) { |
68 | return _str(_str(ss, t), args...); |
69 | } |
70 | |
71 | template <typename... Args> |
72 | struct _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. |
81 | template <> |
82 | struct _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 | |
89 | template <> |
90 | struct _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. |
99 | template <> |
100 | struct _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. |
109 | template <typename... Args> |
110 | inline decltype(auto) str(const Args&... args) { |
111 | return detail::_str_wrapper< |
112 | typename detail::CanonicalizeStrTypes<Args>::type...>::call(args...); |
113 | } |
114 | |
115 | template <class Container> |
116 | inline 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 |
127 | size_t C10_API |
128 | ReplaceAll(std::string& s, c10::string_view from, c10::string_view to); |
129 | |
130 | /// Represents a location in source code (for debugging). |
131 | struct C10_API SourceLocation { |
132 | const char* function; |
133 | const char* file; |
134 | uint32_t line; |
135 | }; |
136 | |
137 | std::ostream& operator<<(std::ostream& out, const SourceLocation& loc); |
138 | |
139 | // unix isprint but insensitive to locale |
140 | inline static bool isPrint(char s) { |
141 | return s > 0x1f && s < 0x7f; |
142 | } |
143 | |
144 | inline 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 | |
200 | C10_CLANG_DIAGNOSTIC_POP() |
201 | |
202 | #endif // C10_UTIL_STRINGUTIL_H_ |
203 | |