StringUtil.h 6.6 KB

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