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