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