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