Line data Source code
1 : #if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION) 2 : #ifndef C10_UTIL_STRINGUTIL_H_ 3 : #define C10_UTIL_STRINGUTIL_H_ 4 : 5 : #include <c10/macros/Macros.h> 6 : #include <c10/util/string_utils.h> 7 : 8 : #include <cstddef> 9 : #include <optional> 10 : #include <ostream> 11 : #include <sstream> 12 : #include <string> 13 : #include <string_view> 14 : #include <type_traits> 15 : #include <vector> 16 : 17 : C10_CLANG_DIAGNOSTIC_PUSH() 18 : #if C10_CLANG_HAS_WARNING("-Wshorten-64-to-32") 19 : C10_CLANG_DIAGNOSTIC_IGNORE("-Wshorten-64-to-32") 20 : #endif 21 : 22 : namespace c10 { 23 : 24 : namespace detail { 25 : 26 : // Obtains the base name from a full path. 27 : C10_API std::string StripBasename(const std::string& full_path); 28 : 29 : C10_API std::string ExcludeFileExtension(const std::string& full_path); 30 : 31 : struct CompileTimeEmptyString { 32 : operator const std::string&() const { 33 : static const std::string empty_string_literal; 34 : return empty_string_literal; 35 : } 36 : operator const char*() const { 37 : return ""; 38 : } 39 : }; 40 : 41 : template <typename T> 42 : struct CanonicalizeStrTypes { 43 : using type = const T&; 44 : }; 45 : 46 : template <size_t N> 47 : // NOLINTNEXTLINE(*c-arrays*) 48 : struct CanonicalizeStrTypes<char[N]> { 49 : using type = const char*; 50 : }; 51 : 52 : inline std::ostream& _str(std::ostream& ss) { 53 : return ss; 54 : } 55 : 56 : template <class T, class = std::ostream&> 57 : struct Streamable : std::false_type {}; 58 : 59 : template <class T> 60 : struct Streamable<T, decltype(std::declval<std::ostream&>() << T{})> 61 : : std::true_type {}; 62 : 63 : template <typename T> 64 : inline std::ostream& _str(std::ostream& ss, const T& t) { 65 : if constexpr (std::is_enum_v<T> && !Streamable<T>::value) { 66 : // NOLINTNEXTLINE(modernize-type-traits) 67 : return _str(ss, static_cast<typename std::underlying_type<T>::type>(t)); 68 : } else { 69 : // NOLINTNEXTLINE(clang-analyzer-core.CallAndMessage) 70 0 : ss << t; 71 0 : return ss; 72 : } 73 : } 74 : 75 : template <typename T> 76 : inline std::ostream& _str(std::ostream& ss, const std::optional<T>& t) { 77 : if (t.has_value()) { 78 : return _str(ss, t.value()); 79 : } 80 : ss << "std::nullopt"; 81 : return ss; 82 : } 83 : // Overloads of _str for wide types; forces narrowing. 84 : C10_API std::ostream& _str(std::ostream& ss, const wchar_t* wCStr); 85 : C10_API std::ostream& _str(std::ostream& ss, const wchar_t& wChar); 86 : C10_API std::ostream& _str(std::ostream& ss, const std::wstring& wString); 87 : 88 : template <> 89 : inline std::ostream& _str<CompileTimeEmptyString>( 90 : std::ostream& ss, 91 : const CompileTimeEmptyString& /*unused*/) { 92 : return ss; 93 : } 94 : 95 : template <typename T, typename... Args> 96 0 : inline std::ostream& _str(std::ostream& ss, const T& t, const Args&... args) { 97 0 : return _str(_str(ss, t), args...); 98 : } 99 : 100 : template <typename... Args> 101 : struct _str_wrapper final { 102 0 : static std::string call(const Args&... args) { 103 0 : std::ostringstream ss; 104 0 : _str(ss, args...); 105 0 : return ss.str(); 106 0 : } 107 : }; 108 : 109 : // Specializations for already-a-string types. 110 : template <> 111 : struct _str_wrapper<std::string> final { 112 : // return by reference to avoid the binary size of a string copy 113 : static const std::string& call(const std::string& str) { 114 : return str; 115 : } 116 : }; 117 : 118 : template <> 119 : struct _str_wrapper<const char*> final { 120 : static const char* call(const char* str) { 121 : return str; 122 : } 123 : }; 124 : 125 : // For c10::str() with an empty argument list (which is common in our assert 126 : // macros), we don't want to pay the binary size for constructing and 127 : // destructing a stringstream or even constructing a string. 128 : template <> 129 : struct _str_wrapper<> final { 130 : static CompileTimeEmptyString call() { 131 : return CompileTimeEmptyString(); 132 : } 133 : }; 134 : 135 : } // namespace detail 136 : 137 : // Convert a list of string-like arguments into a single string. 138 : template <typename... Args> 139 0 : inline auto str(const Args&... args) { 140 : return detail::_str_wrapper< 141 0 : typename detail::CanonicalizeStrTypes<Args>::type...>::call(args...); 142 : } 143 : 144 : template <class Container> 145 : inline std::string Join(const std::string& delimiter, const Container& v) { 146 : std::stringstream s; 147 : int cnt = static_cast<int64_t>(v.size()) - 1; 148 : for (auto i = v.begin(); i != v.end(); ++i, --cnt) { 149 : s << (*i) << (cnt ? delimiter : ""); 150 : } 151 : return std::move(s).str(); 152 : } 153 : 154 : // Replace all occurrences of "from" substring to "to" string. 155 : // Returns number of replacements 156 : size_t C10_API 157 : ReplaceAll(std::string& s, std::string_view from, std::string_view to); 158 : 159 : /// Represents a location in source code (for debugging). 160 : struct C10_API SourceLocation { 161 : const char* function; 162 : const char* file; 163 : uint32_t line; 164 : 165 : static constexpr SourceLocation current( 166 : const char* file = __builtin_FILE(), 167 : const char* function = __builtin_FUNCTION(), 168 : const std::uint_least32_t line = __builtin_LINE()) noexcept { 169 : return {function, file, line}; 170 : } 171 : }; 172 : 173 : std::ostream& operator<<(std::ostream& out, const SourceLocation& loc); 174 : 175 : // unix isprint but insensitive to locale 176 : inline bool isPrint(char s) { 177 : return s > 0x1f && s < 0x7f; 178 : } 179 : 180 : inline void printQuotedString(std::ostream& stmt, const std::string_view str) { 181 : stmt << '"'; 182 : for (auto s : str) { 183 : switch (s) { 184 : case '\\': 185 : stmt << "\\\\"; 186 : break; 187 : case '\'': 188 : stmt << "\\'"; 189 : break; 190 : case '\"': 191 : stmt << "\\\""; 192 : break; 193 : case '\a': 194 : stmt << "\\a"; 195 : break; 196 : case '\b': 197 : stmt << "\\b"; 198 : break; 199 : case '\f': 200 : stmt << "\\f"; 201 : break; 202 : case '\n': 203 : stmt << "\\n"; 204 : break; 205 : case '\r': 206 : stmt << "\\r"; 207 : break; 208 : case '\t': 209 : stmt << "\\t"; 210 : break; 211 : case '\v': 212 : stmt << "\\v"; 213 : break; 214 : default: 215 : if (isPrint(s)) { 216 : stmt << s; 217 : } else { 218 : // C++ io has stateful formatting settings. Messing with 219 : // them is probably worse than doing this manually. 220 : // NOLINTNEXTLINE(*c-arrays*) 221 : char buf[4] = "000"; 222 : // NOLINTNEXTLINE(*narrowing-conversions) 223 : buf[2] += s % 8; 224 : s /= 8; 225 : // NOLINTNEXTLINE(*narrowing-conversions) 226 : buf[1] += s % 8; 227 : s /= 8; 228 : // NOLINTNEXTLINE(*narrowing-conversions) 229 : buf[0] += s; 230 : stmt << "\\" << buf; 231 : } 232 : break; 233 : } 234 : } 235 : stmt << '"'; 236 : } 237 : 238 : template <typename T> 239 : std::optional<T> tryToNumber(const char* symbol) = delete; 240 : template <typename T> 241 : std::optional<T> tryToNumber(const std::string& symbol) = delete; 242 : 243 : /* 244 : * Convert a string to a 64 bit integer. Trailing whitespaces are not supported. 245 : * Similarly, integer string with trailing characters like "123abc" will be 246 : * rejected. 247 : */ 248 : template <> 249 : C10_API std::optional<int64_t> tryToNumber<int64_t>(const char* symbol); 250 : template <> 251 : C10_API std::optional<int64_t> tryToNumber<int64_t>(const std::string& symbol); 252 : 253 : /* 254 : * Convert a string to a double. Trailing whitespaces are not supported. 255 : * Similarly, integer string with trailing characters like "123abc" will 256 : * be rejected. 257 : */ 258 : template <> 259 : C10_API std::optional<double> tryToNumber<double>(const char* symbol); 260 : template <> 261 : C10_API std::optional<double> tryToNumber<double>(const std::string& symbol); 262 : 263 : C10_API std::vector<std::string_view> split( 264 : std::string_view target, 265 : char delimiter); 266 : } // namespace c10 267 : 268 : C10_CLANG_DIAGNOSTIC_POP() 269 : 270 : #endif // C10_UTIL_STRINGUTIL_H_ 271 : 272 : #else 273 : #error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined." 274 : #endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)