/src/CMake/Source/cmStringAlgorithms.cxx
Line | Count | Source |
1 | | /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
2 | | file LICENSE.rst or https://cmake.org/licensing for details. */ |
3 | | #include "cmStringAlgorithms.h" |
4 | | |
5 | | #include <algorithm> |
6 | | #include <cerrno> |
7 | | #include <cstddef> // IWYU pragma: keep |
8 | | #include <cstdio> |
9 | | #include <cstdlib> |
10 | | |
11 | | #include "cmsys/String.h" |
12 | | |
13 | | bool cmStrCaseEq(cm::string_view s1, cm::string_view s2) |
14 | 0 | { |
15 | 0 | if (s1.size() != s2.size()) { |
16 | 0 | return false; |
17 | 0 | } |
18 | | |
19 | 0 | return std::equal(s1.begin(), s1.end(), s2.begin(), [](char a, char b) { |
20 | 0 | return cmsysString_tolower(a) == cmsysString_tolower(b); |
21 | 0 | }); |
22 | 0 | } |
23 | | |
24 | | std::string cmTrimWhitespace(cm::string_view str) |
25 | 1.61k | { |
26 | | // XXX(clang-tidy): This declaration and the next cannot be `const auto*` |
27 | | // because the qualification of `auto` is platform-dependent. |
28 | | // NOLINTNEXTLINE(readability-qualified-auto) |
29 | 1.61k | auto start = str.begin(); |
30 | 119k | while (start != str.end() && cmsysString_isspace(*start)) { |
31 | 118k | ++start; |
32 | 118k | } |
33 | 1.61k | if (start == str.end()) { |
34 | 26 | return std::string(); |
35 | 26 | } |
36 | | // NOLINTNEXTLINE(readability-qualified-auto) |
37 | 1.58k | auto stop = str.end() - 1; |
38 | 13.5k | while (cmsysString_isspace(*stop)) { |
39 | 11.9k | --stop; |
40 | 11.9k | } |
41 | 1.58k | return std::string(start, stop + 1); |
42 | 1.61k | } |
43 | | |
44 | | cm::string_view cmStripWhitespace(cm::string_view str) |
45 | 0 | { |
46 | 0 | std::string::size_type const l = str.size(); |
47 | |
|
48 | 0 | std::string::size_type s = 0; |
49 | 0 | while (s < l && cmsysString_isspace(str[s])) { |
50 | 0 | ++s; |
51 | 0 | } |
52 | 0 | if (s == l) { |
53 | 0 | return cm::string_view{}; |
54 | 0 | } |
55 | 0 | std::string::size_type e = l - 1; |
56 | 0 | while (cmsysString_isspace(str[e])) { |
57 | 0 | --e; |
58 | 0 | } |
59 | 0 | return str.substr(s, e + 1 - s); |
60 | 0 | } |
61 | | |
62 | | std::string cmRemoveQuotes(cm::string_view str) |
63 | 1.61k | { |
64 | | // We process only strings that have two quotes at least. |
65 | | // Also front() and back() are only defined behavior on non empty strings. |
66 | 1.61k | if (str.size() >= 2 && // |
67 | 1.55k | str.front() == '"' && // |
68 | 55 | str.back() == '"') { |
69 | | // Remove a quote from the front and back |
70 | 12 | str.remove_prefix(1); |
71 | 12 | str.remove_suffix(1); |
72 | 12 | } |
73 | 1.61k | return std::string(str); |
74 | 1.61k | } |
75 | | |
76 | | std::string cmEscapeQuotes(cm::string_view str) |
77 | 1.61k | { |
78 | 1.61k | std::string result; |
79 | 1.61k | result.reserve(str.size()); |
80 | 1.94M | for (char const ch : str) { |
81 | 1.94M | if (ch == '"') { |
82 | 2.90k | result += '\\'; |
83 | 2.90k | } |
84 | 1.94M | result += ch; |
85 | 1.94M | } |
86 | 1.61k | return result; |
87 | 1.61k | } |
88 | | |
89 | | namespace { |
90 | | template <std::size_t N, typename T> |
91 | | inline void MakeDigits(cm::string_view& view, char (&digits)[N], |
92 | | char const* pattern, T value) |
93 | 6.86k | { |
94 | 6.86k | int res = std::snprintf(digits, N, pattern, value); |
95 | 6.86k | if (res > 0 && res < static_cast<int>(N)) { |
96 | 6.86k | view = cm::string_view(digits, static_cast<std::size_t>(res)); |
97 | 6.86k | } |
98 | 6.86k | } Unexecuted instantiation: cmStringAlgorithms.cxx:void (anonymous namespace)::MakeDigits<32ul, int>(std::__1::basic_string_view<char, std::__1::char_traits<char> >&, char (&) [32ul], char const*, int) cmStringAlgorithms.cxx:void (anonymous namespace)::MakeDigits<32ul, unsigned int>(std::__1::basic_string_view<char, std::__1::char_traits<char> >&, char (&) [32ul], char const*, unsigned int) Line | Count | Source | 93 | 3 | { | 94 | 3 | int res = std::snprintf(digits, N, pattern, value); | 95 | 3 | if (res > 0 && res < static_cast<int>(N)) { | 96 | 3 | view = cm::string_view(digits, static_cast<std::size_t>(res)); | 97 | 3 | } | 98 | 3 | } |
cmStringAlgorithms.cxx:void (anonymous namespace)::MakeDigits<32ul, long>(std::__1::basic_string_view<char, std::__1::char_traits<char> >&, char (&) [32ul], char const*, long) Line | Count | Source | 93 | 6.86k | { | 94 | 6.86k | int res = std::snprintf(digits, N, pattern, value); | 95 | 6.86k | if (res > 0 && res < static_cast<int>(N)) { | 96 | 6.86k | view = cm::string_view(digits, static_cast<std::size_t>(res)); | 97 | 6.86k | } | 98 | 6.86k | } |
Unexecuted instantiation: cmStringAlgorithms.cxx:void (anonymous namespace)::MakeDigits<32ul, unsigned long>(std::__1::basic_string_view<char, std::__1::char_traits<char> >&, char (&) [32ul], char const*, unsigned long) Unexecuted instantiation: cmStringAlgorithms.cxx:void (anonymous namespace)::MakeDigits<32ul, long long>(std::__1::basic_string_view<char, std::__1::char_traits<char> >&, char (&) [32ul], char const*, long long) Unexecuted instantiation: cmStringAlgorithms.cxx:void (anonymous namespace)::MakeDigits<32ul, unsigned long long>(std::__1::basic_string_view<char, std::__1::char_traits<char> >&, char (&) [32ul], char const*, unsigned long long) Unexecuted instantiation: cmStringAlgorithms.cxx:void (anonymous namespace)::MakeDigits<32ul, double>(std::__1::basic_string_view<char, std::__1::char_traits<char> >&, char (&) [32ul], char const*, double) |
99 | | } // unnamed namespace |
100 | | |
101 | | cmAlphaNum::cmAlphaNum(int val) |
102 | 0 | { |
103 | 0 | MakeDigits(this->View_, this->Digits_, "%i", val); |
104 | 0 | } |
105 | | |
106 | | cmAlphaNum::cmAlphaNum(unsigned int val) |
107 | 3 | { |
108 | 3 | MakeDigits(this->View_, this->Digits_, "%u", val); |
109 | 3 | } |
110 | | |
111 | | cmAlphaNum::cmAlphaNum(long int val) |
112 | 6.86k | { |
113 | 6.86k | MakeDigits(this->View_, this->Digits_, "%li", val); |
114 | 6.86k | } |
115 | | |
116 | | cmAlphaNum::cmAlphaNum(unsigned long int val) |
117 | 0 | { |
118 | 0 | MakeDigits(this->View_, this->Digits_, "%lu", val); |
119 | 0 | } |
120 | | |
121 | | cmAlphaNum::cmAlphaNum(long long int val) |
122 | 0 | { |
123 | 0 | MakeDigits(this->View_, this->Digits_, "%lli", val); |
124 | 0 | } |
125 | | |
126 | | cmAlphaNum::cmAlphaNum(unsigned long long int val) |
127 | 0 | { |
128 | 0 | MakeDigits(this->View_, this->Digits_, "%llu", val); |
129 | 0 | } |
130 | | |
131 | | cmAlphaNum::cmAlphaNum(float val) |
132 | 0 | { |
133 | 0 | MakeDigits(this->View_, this->Digits_, "%g", static_cast<double>(val)); |
134 | 0 | } |
135 | | |
136 | | cmAlphaNum::cmAlphaNum(double val) |
137 | 0 | { |
138 | 0 | MakeDigits(this->View_, this->Digits_, "%g", val); |
139 | 0 | } |
140 | | |
141 | | std::string cmCatViews( |
142 | | std::initializer_list<std::pair<cm::string_view, std::string*>> views) |
143 | 102k | { |
144 | 102k | std::size_t totalSize = 0; |
145 | 102k | std::string* rvalueString = nullptr; |
146 | 102k | std::size_t rvalueStringLength = 0; |
147 | 102k | std::size_t rvalueStringOffset = 0; |
148 | 250k | for (auto const& view : views) { |
149 | | // Find the rvalue string with the largest capacity. |
150 | 250k | if (view.second && |
151 | 33.6k | (!rvalueString || |
152 | 33.6k | view.second->capacity() > rvalueString->capacity())) { |
153 | 33.6k | rvalueString = view.second; |
154 | 33.6k | rvalueStringLength = rvalueString->length(); |
155 | 33.6k | rvalueStringOffset = totalSize; |
156 | 33.6k | } |
157 | 250k | totalSize += view.first.size(); |
158 | 250k | } |
159 | | |
160 | 102k | std::string result; |
161 | 102k | std::string::size_type initialLen = 0; |
162 | 102k | if (rvalueString && rvalueString->capacity() >= totalSize) { |
163 | 26.8k | result = std::move(*rvalueString); |
164 | 75.6k | } else { |
165 | 75.6k | rvalueString = nullptr; |
166 | 75.6k | } |
167 | 102k | result.resize(totalSize); |
168 | 102k | if (rvalueString && rvalueStringOffset > 0) { |
169 | 26.5k | std::copy_backward(result.begin(), result.begin() + rvalueStringLength, |
170 | 26.5k | result.begin() + rvalueStringOffset + |
171 | 26.5k | rvalueStringLength); |
172 | 26.5k | } |
173 | 102k | std::string::iterator sit = result.begin() + initialLen; |
174 | 250k | for (auto const& view : views) { |
175 | 250k | if (rvalueString && view.second == rvalueString) { |
176 | 26.8k | sit += rvalueStringLength; |
177 | 223k | } else { |
178 | 223k | sit = std::copy_n(view.first.data(), view.first.size(), sit); |
179 | 223k | } |
180 | 250k | } |
181 | 102k | return result; |
182 | 102k | } |
183 | | |
184 | | bool cmStrToLong(char const* str, long* value) |
185 | 0 | { |
186 | 0 | errno = 0; |
187 | 0 | char* endp; |
188 | 0 | *value = strtol(str, &endp, 10); |
189 | 0 | return (*endp == '\0') && (endp != str) && (errno == 0); |
190 | 0 | } |
191 | | |
192 | | bool cmStrToLong(std::string const& str, long* value) |
193 | 0 | { |
194 | 0 | return cmStrToLong(str.c_str(), value); |
195 | 0 | } |
196 | | |
197 | | bool cmStrToULong(char const* str, unsigned long* value) |
198 | 0 | { |
199 | 0 | errno = 0; |
200 | 0 | char* endp; |
201 | 0 | while (cmsysString_isspace(*str)) { |
202 | 0 | ++str; |
203 | 0 | } |
204 | 0 | if (*str == '-') { |
205 | 0 | return false; |
206 | 0 | } |
207 | 0 | *value = strtoul(str, &endp, 10); |
208 | 0 | return (*endp == '\0') && (endp != str) && (errno == 0); |
209 | 0 | } |
210 | | |
211 | | bool cmStrToULong(std::string const& str, unsigned long* value) |
212 | 0 | { |
213 | 0 | return cmStrToULong(str.c_str(), value); |
214 | 0 | } |
215 | | |
216 | | bool cmStrToLongLong(char const* str, long long* value) |
217 | 0 | { |
218 | 0 | errno = 0; |
219 | 0 | char* endp; |
220 | 0 | *value = strtoll(str, &endp, 10); |
221 | 0 | return (*endp == '\0') && (endp != str) && (errno == 0); |
222 | 0 | } |
223 | | |
224 | | bool cmStrToLongLong(std::string const& str, long long* value) |
225 | 0 | { |
226 | 0 | return cmStrToLongLong(str.c_str(), value); |
227 | 0 | } |
228 | | |
229 | | bool cmStrToULongLong(char const* str, unsigned long long* value) |
230 | 0 | { |
231 | 0 | errno = 0; |
232 | 0 | char* endp; |
233 | 0 | while (cmsysString_isspace(*str)) { |
234 | 0 | ++str; |
235 | 0 | } |
236 | 0 | if (*str == '-') { |
237 | 0 | return false; |
238 | 0 | } |
239 | 0 | *value = strtoull(str, &endp, 10); |
240 | 0 | return (*endp == '\0') && (endp != str) && (errno == 0); |
241 | 0 | } |
242 | | |
243 | | bool cmStrToULongLong(std::string const& str, unsigned long long* value) |
244 | 0 | { |
245 | 0 | return cmStrToULongLong(str.c_str(), value); |
246 | 0 | } |
247 | | |
248 | | std::string cmJoin(std::vector<std::string> const& rng, |
249 | | cm::string_view separator, cm::string_view initial) |
250 | 3.22k | { |
251 | 3.22k | return cmJoinStrings(rng, separator, initial); |
252 | 3.22k | } |
253 | | |
254 | | std::string cmJoin(cmStringRange rng, cm::string_view separator, |
255 | | cm::string_view initial) |
256 | 0 | { |
257 | 0 | return cmJoinStrings(rng, separator, initial); |
258 | 0 | } |