xref: /aosp_15_r20/external/pytorch/c10/util/StringUtil.cpp (revision da0073e96a02ea20f0ac840b70461e3646d07c45)
1*da0073e9SAndroid Build Coastguard Worker #include <c10/util/StringUtil.h>
2*da0073e9SAndroid Build Coastguard Worker 
3*da0073e9SAndroid Build Coastguard Worker #include <string>
4*da0073e9SAndroid Build Coastguard Worker 
5*da0073e9SAndroid Build Coastguard Worker #ifndef _WIN32
6*da0073e9SAndroid Build Coastguard Worker #include <codecvt>
7*da0073e9SAndroid Build Coastguard Worker #include <locale>
8*da0073e9SAndroid Build Coastguard Worker #else
9*da0073e9SAndroid Build Coastguard Worker #include <c10/util/Unicode.h>
10*da0073e9SAndroid Build Coastguard Worker #endif
11*da0073e9SAndroid Build Coastguard Worker 
12*da0073e9SAndroid Build Coastguard Worker namespace c10 {
13*da0073e9SAndroid Build Coastguard Worker 
14*da0073e9SAndroid Build Coastguard Worker namespace detail {
15*da0073e9SAndroid Build Coastguard Worker 
StripBasename(const std::string & full_path)16*da0073e9SAndroid Build Coastguard Worker std::string StripBasename(const std::string& full_path) {
17*da0073e9SAndroid Build Coastguard Worker #ifdef _WIN32
18*da0073e9SAndroid Build Coastguard Worker   const std::string separators("/\\");
19*da0073e9SAndroid Build Coastguard Worker #else
20*da0073e9SAndroid Build Coastguard Worker   const std::string separators("/");
21*da0073e9SAndroid Build Coastguard Worker #endif
22*da0073e9SAndroid Build Coastguard Worker   size_t pos = full_path.find_last_of(separators);
23*da0073e9SAndroid Build Coastguard Worker   if (pos != std::string::npos) {
24*da0073e9SAndroid Build Coastguard Worker     return full_path.substr(pos + 1, std::string::npos);
25*da0073e9SAndroid Build Coastguard Worker   } else {
26*da0073e9SAndroid Build Coastguard Worker     return full_path;
27*da0073e9SAndroid Build Coastguard Worker   }
28*da0073e9SAndroid Build Coastguard Worker }
29*da0073e9SAndroid Build Coastguard Worker 
ExcludeFileExtension(const std::string & file_name)30*da0073e9SAndroid Build Coastguard Worker std::string ExcludeFileExtension(const std::string& file_name) {
31*da0073e9SAndroid Build Coastguard Worker   const char sep = '.';
32*da0073e9SAndroid Build Coastguard Worker   auto end_index = file_name.find_last_of(sep) == std::string::npos
33*da0073e9SAndroid Build Coastguard Worker       ? -1
34*da0073e9SAndroid Build Coastguard Worker       : file_name.find_last_of(sep);
35*da0073e9SAndroid Build Coastguard Worker   return file_name.substr(0, end_index);
36*da0073e9SAndroid Build Coastguard Worker }
37*da0073e9SAndroid Build Coastguard Worker 
38*da0073e9SAndroid Build Coastguard Worker // Narrows the wstr argument and then passes it to _str.
39*da0073e9SAndroid Build Coastguard Worker // Assumes that the input (wide) text is encoded as UTF-16.
40*da0073e9SAndroid Build Coastguard Worker std::ostream& _strFromWide(std::ostream& ss, const std::wstring& wString);
41*da0073e9SAndroid Build Coastguard Worker 
42*da0073e9SAndroid Build Coastguard Worker #ifndef _WIN32
43*da0073e9SAndroid Build Coastguard Worker 
44*da0073e9SAndroid Build Coastguard Worker #pragma GCC diagnostic push
45*da0073e9SAndroid Build Coastguard Worker #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
46*da0073e9SAndroid Build Coastguard Worker // TODO (huydhn) https://en.cppreference.com/w/cpp/header/codecvt has been
47*da0073e9SAndroid Build Coastguard Worker // deprecated in C++17 but there is no alternative yet, so I just ack it
_strFromWide(std::ostream & ss,const std::wstring & wString)48*da0073e9SAndroid Build Coastguard Worker std::ostream& _strFromWide(std::ostream& ss, const std::wstring& wString) {
49*da0073e9SAndroid Build Coastguard Worker   std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
50*da0073e9SAndroid Build Coastguard Worker   return _str(ss, converter.to_bytes(wString));
51*da0073e9SAndroid Build Coastguard Worker }
52*da0073e9SAndroid Build Coastguard Worker #pragma GCC diagnostic pop
53*da0073e9SAndroid Build Coastguard Worker 
54*da0073e9SAndroid Build Coastguard Worker #else // #ifndef _WIN32
55*da0073e9SAndroid Build Coastguard Worker // The WIN32 implementation of wstring_convert leaks memory; see
56*da0073e9SAndroid Build Coastguard Worker // https://github.com/microsoft/STL/issues/443
57*da0073e9SAndroid Build Coastguard Worker 
_strFromWide(std::ostream & ss,const std::wstring & wString)58*da0073e9SAndroid Build Coastguard Worker std::ostream& _strFromWide(std::ostream& ss, const std::wstring& wString) {
59*da0073e9SAndroid Build Coastguard Worker   return _str(ss, u16u8(wString));
60*da0073e9SAndroid Build Coastguard Worker }
61*da0073e9SAndroid Build Coastguard Worker 
62*da0073e9SAndroid Build Coastguard Worker #endif // _WIN32
63*da0073e9SAndroid Build Coastguard Worker 
_str(std::ostream & ss,const wchar_t * wCStr)64*da0073e9SAndroid Build Coastguard Worker std::ostream& _str(std::ostream& ss, const wchar_t* wCStr) {
65*da0073e9SAndroid Build Coastguard Worker   return _strFromWide(ss, std::wstring(wCStr));
66*da0073e9SAndroid Build Coastguard Worker }
_str(std::ostream & ss,const wchar_t & wChar)67*da0073e9SAndroid Build Coastguard Worker std::ostream& _str(std::ostream& ss, const wchar_t& wChar) {
68*da0073e9SAndroid Build Coastguard Worker   return _strFromWide(ss, std::wstring(1, wChar));
69*da0073e9SAndroid Build Coastguard Worker }
_str(std::ostream & ss,const std::wstring & wString)70*da0073e9SAndroid Build Coastguard Worker std::ostream& _str(std::ostream& ss, const std::wstring& wString) {
71*da0073e9SAndroid Build Coastguard Worker   return _strFromWide(ss, wString);
72*da0073e9SAndroid Build Coastguard Worker }
73*da0073e9SAndroid Build Coastguard Worker 
74*da0073e9SAndroid Build Coastguard Worker } // namespace detail
75*da0073e9SAndroid Build Coastguard Worker 
operator <<(std::ostream & out,const SourceLocation & loc)76*da0073e9SAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& out, const SourceLocation& loc) {
77*da0073e9SAndroid Build Coastguard Worker   out << loc.function << " at " << loc.file << ":" << loc.line;
78*da0073e9SAndroid Build Coastguard Worker   return out;
79*da0073e9SAndroid Build Coastguard Worker }
80*da0073e9SAndroid Build Coastguard Worker 
ReplaceAll(std::string & s,c10::string_view from,c10::string_view to)81*da0073e9SAndroid Build Coastguard Worker size_t ReplaceAll(std::string& s, c10::string_view from, c10::string_view to) {
82*da0073e9SAndroid Build Coastguard Worker   if (from.empty()) {
83*da0073e9SAndroid Build Coastguard Worker     return 0;
84*da0073e9SAndroid Build Coastguard Worker   }
85*da0073e9SAndroid Build Coastguard Worker 
86*da0073e9SAndroid Build Coastguard Worker   size_t numReplaced = 0;
87*da0073e9SAndroid Build Coastguard Worker   std::string::size_type last_pos = 0u;
88*da0073e9SAndroid Build Coastguard Worker   std::string::size_type cur_pos = 0u;
89*da0073e9SAndroid Build Coastguard Worker   std::string::size_type write_pos = 0u;
90*da0073e9SAndroid Build Coastguard Worker   const c10::string_view input(s);
91*da0073e9SAndroid Build Coastguard Worker 
92*da0073e9SAndroid Build Coastguard Worker   if (from.size() >= to.size()) {
93*da0073e9SAndroid Build Coastguard Worker     // If the replacement string is not larger than the original, we
94*da0073e9SAndroid Build Coastguard Worker     // can do the replacement in-place without allocating new storage.
95*da0073e9SAndroid Build Coastguard Worker     char* s_data = &s[0];
96*da0073e9SAndroid Build Coastguard Worker 
97*da0073e9SAndroid Build Coastguard Worker     while ((cur_pos = s.find(from.data(), last_pos, from.size())) !=
98*da0073e9SAndroid Build Coastguard Worker            std::string::npos) {
99*da0073e9SAndroid Build Coastguard Worker       ++numReplaced;
100*da0073e9SAndroid Build Coastguard Worker       // Append input between replaced sub-strings
101*da0073e9SAndroid Build Coastguard Worker       if (write_pos != last_pos) {
102*da0073e9SAndroid Build Coastguard Worker         std::copy(s_data + last_pos, s_data + cur_pos, s_data + write_pos);
103*da0073e9SAndroid Build Coastguard Worker       }
104*da0073e9SAndroid Build Coastguard Worker       write_pos += cur_pos - last_pos;
105*da0073e9SAndroid Build Coastguard Worker       // Append the replacement sub-string
106*da0073e9SAndroid Build Coastguard Worker       std::copy(to.begin(), to.end(), s_data + write_pos);
107*da0073e9SAndroid Build Coastguard Worker       write_pos += to.size();
108*da0073e9SAndroid Build Coastguard Worker       // Start search from next character after `from`
109*da0073e9SAndroid Build Coastguard Worker       last_pos = cur_pos + from.size();
110*da0073e9SAndroid Build Coastguard Worker     }
111*da0073e9SAndroid Build Coastguard Worker 
112*da0073e9SAndroid Build Coastguard Worker     // Append any remaining input after replaced sub-strings
113*da0073e9SAndroid Build Coastguard Worker     if (write_pos != last_pos) {
114*da0073e9SAndroid Build Coastguard Worker       std::copy(s_data + last_pos, s_data + input.size(), s_data + write_pos);
115*da0073e9SAndroid Build Coastguard Worker       write_pos += input.size() - last_pos;
116*da0073e9SAndroid Build Coastguard Worker       s.resize(write_pos);
117*da0073e9SAndroid Build Coastguard Worker     }
118*da0073e9SAndroid Build Coastguard Worker     return numReplaced;
119*da0073e9SAndroid Build Coastguard Worker   }
120*da0073e9SAndroid Build Coastguard Worker 
121*da0073e9SAndroid Build Coastguard Worker   // Otherwise, do an out-of-place replacement in a temporary buffer
122*da0073e9SAndroid Build Coastguard Worker   std::string buffer;
123*da0073e9SAndroid Build Coastguard Worker 
124*da0073e9SAndroid Build Coastguard Worker   while ((cur_pos = s.find(from.data(), last_pos, from.size())) !=
125*da0073e9SAndroid Build Coastguard Worker          std::string::npos) {
126*da0073e9SAndroid Build Coastguard Worker     ++numReplaced;
127*da0073e9SAndroid Build Coastguard Worker     // Append input between replaced sub-strings
128*da0073e9SAndroid Build Coastguard Worker     buffer.append(input.begin() + last_pos, input.begin() + cur_pos);
129*da0073e9SAndroid Build Coastguard Worker     // Append the replacement sub-string
130*da0073e9SAndroid Build Coastguard Worker     buffer.append(to.begin(), to.end());
131*da0073e9SAndroid Build Coastguard Worker     // Start search from next character after `from`
132*da0073e9SAndroid Build Coastguard Worker     last_pos = cur_pos + from.size();
133*da0073e9SAndroid Build Coastguard Worker   }
134*da0073e9SAndroid Build Coastguard Worker   if (numReplaced == 0) {
135*da0073e9SAndroid Build Coastguard Worker     // If nothing was replaced, don't modify the input
136*da0073e9SAndroid Build Coastguard Worker     return 0;
137*da0073e9SAndroid Build Coastguard Worker   }
138*da0073e9SAndroid Build Coastguard Worker   // Append any remaining input after replaced sub-strings
139*da0073e9SAndroid Build Coastguard Worker   buffer.append(input.begin() + last_pos, input.end());
140*da0073e9SAndroid Build Coastguard Worker   s = std::move(buffer);
141*da0073e9SAndroid Build Coastguard Worker   return numReplaced;
142*da0073e9SAndroid Build Coastguard Worker }
143*da0073e9SAndroid Build Coastguard Worker 
144*da0073e9SAndroid Build Coastguard Worker } // namespace c10
145