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 std::move(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 : [[nodiscard]] 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 : [[nodiscard]] inline std::string Join( 146 : const std::string& delimiter, 147 : const Container& v) { 148 : std::stringstream s; 149 : int cnt = static_cast<int64_t>(v.size()) - 1; 150 : for (auto i = v.begin(); i != v.end(); ++i, --cnt) { 151 : s << (*i) << (cnt ? delimiter : ""); 152 : } 153 : return std::move(s).str(); 154 : } 155 : 156 : // Replace all occurrences of "from" substring to "to" string. 157 : // Returns number of replacements 158 : size_t C10_API 159 : ReplaceAll(std::string& s, std::string_view from, std::string_view to); 160 : 161 : /// Represents a location in source code (for debugging). 162 : struct C10_API SourceLocation { 163 : const char* function; 164 : const char* file; 165 : uint32_t line; 166 : 167 : [[nodiscard]] static constexpr SourceLocation current( 168 : const char* file = __builtin_FILE(), 169 : const char* function = __builtin_FUNCTION(), 170 : const std::uint_least32_t line = __builtin_LINE()) noexcept { 171 : return {.function = function, .file = file, .line = line}; 172 : } 173 : }; 174 : 175 : std::ostream& operator<<(std::ostream& out, const SourceLocation& loc); 176 : 177 : // unix isprint but insensitive to locale 178 : [[nodiscard]] inline bool isPrint(char s) { 179 : return s > 0x1f && s < 0x7f; 180 : } 181 : 182 : inline void printQuotedString(std::ostream& stmt, const std::string_view str) { 183 : stmt << '"'; 184 : for (auto s : str) { 185 : switch (s) { 186 : case '\\': 187 : stmt << "\\\\"; 188 : break; 189 : case '\'': 190 : stmt << "\\'"; 191 : break; 192 : case '\"': 193 : stmt << "\\\""; 194 : break; 195 : case '\a': 196 : stmt << "\\a"; 197 : break; 198 : case '\b': 199 : stmt << "\\b"; 200 : break; 201 : case '\f': 202 : stmt << "\\f"; 203 : break; 204 : case '\n': 205 : stmt << "\\n"; 206 : break; 207 : case '\r': 208 : stmt << "\\r"; 209 : break; 210 : case '\t': 211 : stmt << "\\t"; 212 : break; 213 : case '\v': 214 : stmt << "\\v"; 215 : break; 216 : default: 217 : if (isPrint(s)) { 218 : stmt << s; 219 : } else { 220 : // C++ io has stateful formatting settings. Messing with 221 : // them is probably worse than doing this manually. 222 : // NOLINTNEXTLINE(*c-arrays*) 223 : char buf[4] = "000"; 224 : // NOLINTNEXTLINE(*narrowing-conversions) 225 : buf[2] += s % 8; 226 : s /= 8; 227 : // NOLINTNEXTLINE(*narrowing-conversions) 228 : buf[1] += s % 8; 229 : s /= 8; 230 : // NOLINTNEXTLINE(*narrowing-conversions) 231 : buf[0] += s; 232 : stmt << '\\' << buf; 233 : } 234 : break; 235 : } 236 : } 237 : stmt << '"'; 238 : } 239 : 240 : template <typename T> 241 : std::optional<T> tryToNumber(const char* symbol) = delete; 242 : template <typename T> 243 : std::optional<T> tryToNumber(const std::string& symbol) = delete; 244 : 245 : /* 246 : * Convert a string to a 64 bit integer. Trailing whitespaces are not supported. 247 : * Similarly, integer string with trailing characters like "123abc" will be 248 : * rejected. 249 : */ 250 : template <> 251 : [[nodiscard]] C10_API std::optional<int64_t> tryToNumber<int64_t>( 252 : const char* symbol); 253 : template <> 254 : [[nodiscard]] C10_API std::optional<int64_t> tryToNumber<int64_t>( 255 : const std::string& symbol); 256 : 257 : /* 258 : * Convert a string to a double. Trailing whitespaces are not supported. 259 : * Similarly, integer string with trailing characters like "123abc" will 260 : * be rejected. 261 : */ 262 : template <> 263 : [[nodiscard]] C10_API std::optional<double> tryToNumber<double>( 264 : const char* symbol); 265 : template <> 266 : [[nodiscard]] C10_API std::optional<double> tryToNumber<double>( 267 : const std::string& symbol); 268 : 269 : [[nodiscard]] C10_API std::vector<std::string_view> split( 270 : std::string_view target, 271 : char delimiter); 272 : } // namespace c10 273 : 274 : C10_CLANG_DIAGNOSTIC_POP() 275 : 276 : #endif // C10_UTIL_STRINGUTIL_H_ 277 : 278 : #else 279 : #error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined." 280 : #endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)