/src/mozilla-central/xpcom/string/nsTStringObsolete.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #include "nsTArray.h" |
8 | | #include "nsASCIIMask.h" |
9 | | #include "mozilla/CheckedInt.h" |
10 | | |
11 | | /** |
12 | | * nsTString::Find |
13 | | * |
14 | | * aOffset specifies starting index |
15 | | * aCount specifies number of string compares (iterations) |
16 | | */ |
17 | | template <typename T> |
18 | | int32_t |
19 | | nsTString<T>::Find(const nsTString<char>& aString, bool aIgnoreCase, int32_t aOffset, int32_t aCount) const |
20 | 6.04k | { |
21 | 6.04k | // this method changes the meaning of aOffset and aCount: |
22 | 6.04k | Find_ComputeSearchRange(this->mLength, aString.Length(), aOffset, aCount); |
23 | 6.04k | |
24 | 6.04k | int32_t result = FindSubstring(this->mData + aOffset, aCount, aString.get(), aString.Length(), aIgnoreCase); |
25 | 6.04k | if (result != kNotFound) |
26 | 6.04k | result += aOffset; |
27 | 6.04k | return result; |
28 | 6.04k | } nsTString<char>::Find(nsTString<char> const&, bool, int, int) const Line | Count | Source | 20 | 6.04k | { | 21 | 6.04k | // this method changes the meaning of aOffset and aCount: | 22 | 6.04k | Find_ComputeSearchRange(this->mLength, aString.Length(), aOffset, aCount); | 23 | 6.04k | | 24 | 6.04k | int32_t result = FindSubstring(this->mData + aOffset, aCount, aString.get(), aString.Length(), aIgnoreCase); | 25 | 6.04k | if (result != kNotFound) | 26 | 6.04k | result += aOffset; | 27 | 6.04k | return result; | 28 | 6.04k | } |
Unexecuted instantiation: nsTString<char16_t>::Find(nsTString<char> const&, bool, int, int) const |
29 | | |
30 | | template <typename T> |
31 | | int32_t |
32 | | nsTString<T>::Find(const char* aString, bool aIgnoreCase, int32_t aOffset, int32_t aCount) const |
33 | 875 | { |
34 | 875 | return Find(nsTDependentString<char>(aString), aIgnoreCase, aOffset, aCount); |
35 | 875 | } nsTString<char>::Find(char const*, bool, int, int) const Line | Count | Source | 33 | 875 | { | 34 | 875 | return Find(nsTDependentString<char>(aString), aIgnoreCase, aOffset, aCount); | 35 | 875 | } |
Unexecuted instantiation: nsTString<char16_t>::Find(char const*, bool, int, int) const |
36 | | |
37 | | |
38 | | /** |
39 | | * nsTString::RFind |
40 | | * |
41 | | * aOffset specifies starting index |
42 | | * aCount specifies number of string compares (iterations) |
43 | | */ |
44 | | template <typename T> |
45 | | int32_t |
46 | | nsTString<T>::RFind(const nsTString<char>& aString, bool aIgnoreCase, int32_t aOffset, int32_t aCount) const |
47 | 0 | { |
48 | 0 | // this method changes the meaning of aOffset and aCount: |
49 | 0 | RFind_ComputeSearchRange(this->mLength, aString.Length(), aOffset, aCount); |
50 | 0 |
|
51 | 0 | int32_t result = RFindSubstring(this->mData + aOffset, aCount, aString.get(), aString.Length(), aIgnoreCase); |
52 | 0 | if (result != kNotFound) |
53 | 0 | result += aOffset; |
54 | 0 | return result; |
55 | 0 | } Unexecuted instantiation: nsTString<char>::RFind(nsTString<char> const&, bool, int, int) const Unexecuted instantiation: nsTString<char16_t>::RFind(nsTString<char> const&, bool, int, int) const |
56 | | |
57 | | template <typename T> |
58 | | int32_t |
59 | | nsTString<T>::RFind(const char* aString, bool aIgnoreCase, int32_t aOffset, int32_t aCount) const |
60 | 0 | { |
61 | 0 | return RFind(nsTDependentString<char>(aString), aIgnoreCase, aOffset, aCount); |
62 | 0 | } Unexecuted instantiation: nsTString<char>::RFind(char const*, bool, int, int) const Unexecuted instantiation: nsTString<char16_t>::RFind(char const*, bool, int, int) const |
63 | | |
64 | | |
65 | | /** |
66 | | * nsTString::RFindChar |
67 | | */ |
68 | | template <typename T> |
69 | | int32_t |
70 | | nsTString<T>::RFindChar(char16_t aChar, int32_t aOffset, int32_t aCount) const |
71 | 337 | { |
72 | 337 | return nsBufferRoutines<T>::rfind_char(this->mData, this->mLength, aOffset, aChar, aCount); |
73 | 337 | } nsTString<char>::RFindChar(char16_t, int, int) const Line | Count | Source | 71 | 337 | { | 72 | 337 | return nsBufferRoutines<T>::rfind_char(this->mData, this->mLength, aOffset, aChar, aCount); | 73 | 337 | } |
Unexecuted instantiation: nsTString<char16_t>::RFindChar(char16_t, int, int) const |
74 | | |
75 | | |
76 | | /** |
77 | | * nsTString::FindCharInSet |
78 | | */ |
79 | | |
80 | | template <typename T> |
81 | | int32_t |
82 | | nsTString<T>::FindCharInSet(const char_type* aSet, int32_t aOffset) const |
83 | 34.0k | { |
84 | 34.0k | if (aOffset < 0) |
85 | 0 | aOffset = 0; |
86 | 34.0k | else if (aOffset >= int32_t(this->mLength)) |
87 | 699 | return kNotFound; |
88 | 33.3k | |
89 | 33.3k | int32_t result = ::FindCharInSet(this->mData + aOffset, this->mLength - aOffset, aSet); |
90 | 33.3k | if (result != kNotFound) |
91 | 33.3k | result += aOffset; |
92 | 33.3k | return result; |
93 | 33.3k | } nsTString<char>::FindCharInSet(char const*, int) const Line | Count | Source | 83 | 7.26k | { | 84 | 7.26k | if (aOffset < 0) | 85 | 0 | aOffset = 0; | 86 | 7.26k | else if (aOffset >= int32_t(this->mLength)) | 87 | 699 | return kNotFound; | 88 | 6.56k | | 89 | 6.56k | int32_t result = ::FindCharInSet(this->mData + aOffset, this->mLength - aOffset, aSet); | 90 | 6.56k | if (result != kNotFound) | 91 | 6.56k | result += aOffset; | 92 | 6.56k | return result; | 93 | 6.56k | } |
nsTString<char16_t>::FindCharInSet(char16_t const*, int) const Line | Count | Source | 83 | 26.8k | { | 84 | 26.8k | if (aOffset < 0) | 85 | 0 | aOffset = 0; | 86 | 26.8k | else if (aOffset >= int32_t(this->mLength)) | 87 | 0 | return kNotFound; | 88 | 26.8k | | 89 | 26.8k | int32_t result = ::FindCharInSet(this->mData + aOffset, this->mLength - aOffset, aSet); | 90 | 26.8k | if (result != kNotFound) | 91 | 26.8k | result += aOffset; | 92 | 26.8k | return result; | 93 | 26.8k | } |
|
94 | | |
95 | | |
96 | | /** |
97 | | * nsTString::RFindCharInSet |
98 | | */ |
99 | | |
100 | | template <typename T> |
101 | | int32_t |
102 | | nsTString<T>::RFindCharInSet(const char_type* aSet, int32_t aOffset) const |
103 | 12 | { |
104 | 12 | // We want to pass a "data length" to ::RFindCharInSet |
105 | 12 | if (aOffset < 0 || aOffset > int32_t(this->mLength)) |
106 | 12 | aOffset = this->mLength; |
107 | 0 | else |
108 | 0 | ++aOffset; |
109 | 12 | |
110 | 12 | return ::RFindCharInSet(this->mData, aOffset, aSet); |
111 | 12 | } nsTString<char>::RFindCharInSet(char const*, int) const Line | Count | Source | 103 | 12 | { | 104 | 12 | // We want to pass a "data length" to ::RFindCharInSet | 105 | 12 | if (aOffset < 0 || aOffset > int32_t(this->mLength)) | 106 | 12 | aOffset = this->mLength; | 107 | 0 | else | 108 | 0 | ++aOffset; | 109 | 12 | | 110 | 12 | return ::RFindCharInSet(this->mData, aOffset, aSet); | 111 | 12 | } |
Unexecuted instantiation: nsTString<char16_t>::RFindCharInSet(char16_t const*, int) const |
112 | | |
113 | | |
114 | | /** |
115 | | * nsTString::Mid |
116 | | */ |
117 | | |
118 | | template <typename T> |
119 | | typename nsTString<T>::size_type |
120 | | nsTString<T>::Mid(self_type& aResult, index_type aStartPos, size_type aLengthToCopy) const |
121 | 0 | { |
122 | 0 | if (aStartPos == 0 && aLengthToCopy >= this->mLength) |
123 | 0 | aResult = *this; |
124 | 0 | else |
125 | 0 | aResult = Substring(*this, aStartPos, aLengthToCopy); |
126 | 0 |
|
127 | 0 | return aResult.mLength; |
128 | 0 | } Unexecuted instantiation: nsTString<char>::Mid(nsTString<char>&, unsigned int, unsigned int) const Unexecuted instantiation: nsTString<char16_t>::Mid(nsTString<char16_t>&, unsigned int, unsigned int) const |
129 | | |
130 | | |
131 | | /** |
132 | | * nsTString::SetCharAt |
133 | | */ |
134 | | |
135 | | template <typename T> |
136 | | bool |
137 | | nsTString<T>::SetCharAt(char16_t aChar, uint32_t aIndex) |
138 | 0 | { |
139 | 0 | if (aIndex >= this->mLength) |
140 | 0 | return false; |
141 | 0 | |
142 | 0 | if (!this->EnsureMutable()) |
143 | 0 | this->AllocFailed(this->mLength); |
144 | 0 |
|
145 | 0 | this->mData[aIndex] = char_type(aChar); |
146 | 0 | return true; |
147 | 0 | } Unexecuted instantiation: nsTString<char>::SetCharAt(char16_t, unsigned int) Unexecuted instantiation: nsTString<char16_t>::SetCharAt(char16_t, unsigned int) |
148 | | |
149 | | |
150 | | /** |
151 | | * nsTString::StripChars,StripChar,StripWhitespace |
152 | | */ |
153 | | |
154 | | template<typename T> |
155 | | template<typename Q, typename EnableIfChar16> |
156 | | void |
157 | | nsTString<T>::StripChars(const incompatible_char_type* aSet) |
158 | 0 | { |
159 | 0 | if (!StripChars(aSet, mozilla::fallible)) { |
160 | 0 | this->AllocFailed(this->mLength); |
161 | 0 | } |
162 | 0 | } |
163 | | |
164 | | template<typename T> |
165 | | template<typename Q, typename EnableIfChar16> |
166 | | bool |
167 | | nsTString<T>::StripChars(const incompatible_char_type* aSet, const fallible_t&) |
168 | 0 | { |
169 | 0 | if (!this->EnsureMutable()) { |
170 | 0 | return false; |
171 | 0 | } |
172 | 0 | |
173 | 0 | this->mLength = nsBufferRoutines<T>::strip_chars(this->mData, this->mLength, aSet); |
174 | 0 | return true; |
175 | 0 | } |
176 | | |
177 | | template<typename T> |
178 | | void |
179 | | nsTString<T>::StripChars(const char_type* aSet) |
180 | 1 | { |
181 | 1 | nsTSubstring<T>::StripChars(aSet); |
182 | 1 | } nsTString<char>::StripChars(char const*) Line | Count | Source | 180 | 1 | { | 181 | 1 | nsTSubstring<T>::StripChars(aSet); | 182 | 1 | } |
Unexecuted instantiation: nsTString<char16_t>::StripChars(char16_t const*) |
183 | | |
184 | | template <typename T> |
185 | | void |
186 | | nsTString<T>::StripWhitespace() |
187 | 0 | { |
188 | 0 | if (!StripWhitespace(mozilla::fallible)) { |
189 | 0 | this->AllocFailed(this->mLength); |
190 | 0 | } |
191 | 0 | } Unexecuted instantiation: nsTString<char>::StripWhitespace() Unexecuted instantiation: nsTString<char16_t>::StripWhitespace() |
192 | | |
193 | | template <typename T> |
194 | | bool |
195 | | nsTString<T>::StripWhitespace(const fallible_t&) |
196 | 633 | { |
197 | 633 | if (!this->EnsureMutable()) { |
198 | 0 | return false; |
199 | 0 | } |
200 | 633 | |
201 | 633 | this->StripTaggedASCII(mozilla::ASCIIMask::MaskWhitespace()); |
202 | 633 | return true; |
203 | 633 | } nsTString<char>::StripWhitespace(std::nothrow_t const&) Line | Count | Source | 196 | 633 | { | 197 | 633 | if (!this->EnsureMutable()) { | 198 | 0 | return false; | 199 | 0 | } | 200 | 633 | | 201 | 633 | this->StripTaggedASCII(mozilla::ASCIIMask::MaskWhitespace()); | 202 | 633 | return true; | 203 | 633 | } |
Unexecuted instantiation: nsTString<char16_t>::StripWhitespace(std::nothrow_t const&) |
204 | | |
205 | | /** |
206 | | * nsTString::ReplaceChar,ReplaceSubstring |
207 | | */ |
208 | | |
209 | | template <typename T> |
210 | | void |
211 | | nsTString<T>::ReplaceChar(char_type aOldChar, char_type aNewChar) |
212 | 12 | { |
213 | 12 | if (!this->EnsureMutable()) // XXX do this lazily? |
214 | 0 | this->AllocFailed(this->mLength); |
215 | 12 | |
216 | 102 | for (uint32_t i=0; i<this->mLength; ++i) |
217 | 90 | { |
218 | 90 | if (this->mData[i] == aOldChar) |
219 | 12 | this->mData[i] = aNewChar; |
220 | 90 | } |
221 | 12 | } nsTString<char>::ReplaceChar(char, char) Line | Count | Source | 212 | 12 | { | 213 | 12 | if (!this->EnsureMutable()) // XXX do this lazily? | 214 | 0 | this->AllocFailed(this->mLength); | 215 | 12 | | 216 | 102 | for (uint32_t i=0; i<this->mLength; ++i) | 217 | 90 | { | 218 | 90 | if (this->mData[i] == aOldChar) | 219 | 12 | this->mData[i] = aNewChar; | 220 | 90 | } | 221 | 12 | } |
Unexecuted instantiation: nsTString<char16_t>::ReplaceChar(char16_t, char16_t) |
222 | | |
223 | | template <typename T> |
224 | | void |
225 | | nsTString<T>::ReplaceChar(const char_type* aSet, char_type aNewChar) |
226 | 0 | { |
227 | 0 | if (!this->EnsureMutable()) // XXX do this lazily? |
228 | 0 | this->AllocFailed(this->mLength); |
229 | 0 |
|
230 | 0 | char_type* data = this->mData; |
231 | 0 | uint32_t lenRemaining = this->mLength; |
232 | 0 |
|
233 | 0 | while (lenRemaining) |
234 | 0 | { |
235 | 0 | int32_t i = ::FindCharInSet(data, lenRemaining, aSet); |
236 | 0 | if (i == kNotFound) |
237 | 0 | break; |
238 | 0 | |
239 | 0 | data[i++] = aNewChar; |
240 | 0 | data += i; |
241 | 0 | lenRemaining -= i; |
242 | 0 | } |
243 | 0 | } Unexecuted instantiation: nsTString<char>::ReplaceChar(char const*, char) Unexecuted instantiation: nsTString<char16_t>::ReplaceChar(char16_t const*, char16_t) |
244 | | |
245 | | void ReleaseData(void* aData, nsAString::DataFlags aFlags); |
246 | | |
247 | | template <typename T> |
248 | | void |
249 | | nsTString<T>::ReplaceSubstring(const char_type* aTarget, |
250 | | const char_type* aNewValue) |
251 | 349 | { |
252 | 349 | ReplaceSubstring(nsTDependentString<T>(aTarget), |
253 | 349 | nsTDependentString<T>(aNewValue)); |
254 | 349 | } nsTString<char>::ReplaceSubstring(char const*, char const*) Line | Count | Source | 251 | 349 | { | 252 | 349 | ReplaceSubstring(nsTDependentString<T>(aTarget), | 253 | 349 | nsTDependentString<T>(aNewValue)); | 254 | 349 | } |
Unexecuted instantiation: nsTString<char16_t>::ReplaceSubstring(char16_t const*, char16_t const*) |
255 | | |
256 | | template <typename T> |
257 | | bool |
258 | | nsTString<T>::ReplaceSubstring(const char_type* aTarget, |
259 | | const char_type* aNewValue, |
260 | | const fallible_t& aFallible) |
261 | 0 | { |
262 | 0 | return ReplaceSubstring(nsTDependentString<T>(aTarget), |
263 | 0 | nsTDependentString<T>(aNewValue), |
264 | 0 | aFallible); |
265 | 0 | } Unexecuted instantiation: nsTString<char>::ReplaceSubstring(char const*, char const*, std::nothrow_t const&) Unexecuted instantiation: nsTString<char16_t>::ReplaceSubstring(char16_t const*, char16_t const*, std::nothrow_t const&) |
266 | | |
267 | | template <typename T> |
268 | | void |
269 | | nsTString<T>::ReplaceSubstring(const self_type& aTarget, |
270 | | const self_type& aNewValue) |
271 | 349 | { |
272 | 349 | if (!ReplaceSubstring(aTarget, aNewValue, mozilla::fallible)) { |
273 | 0 | // Note that this may wildly underestimate the allocation that failed, as |
274 | 0 | // we could have been replacing multiple copies of aTarget. |
275 | 0 | this->AllocFailed(this->mLength + (aNewValue.Length() - aTarget.Length())); |
276 | 0 | } |
277 | 349 | } nsTString<char>::ReplaceSubstring(nsTString<char> const&, nsTString<char> const&) Line | Count | Source | 271 | 349 | { | 272 | 349 | if (!ReplaceSubstring(aTarget, aNewValue, mozilla::fallible)) { | 273 | 0 | // Note that this may wildly underestimate the allocation that failed, as | 274 | 0 | // we could have been replacing multiple copies of aTarget. | 275 | 0 | this->AllocFailed(this->mLength + (aNewValue.Length() - aTarget.Length())); | 276 | 0 | } | 277 | 349 | } |
Unexecuted instantiation: nsTString<char16_t>::ReplaceSubstring(nsTString<char16_t> const&, nsTString<char16_t> const&) |
278 | | |
279 | | template <typename T> |
280 | | bool |
281 | | nsTString<T>::ReplaceSubstring(const self_type& aTarget, |
282 | | const self_type& aNewValue, |
283 | | const fallible_t&) |
284 | 349 | { |
285 | 349 | if (aTarget.Length() == 0) |
286 | 0 | return true; |
287 | 349 | |
288 | 349 | // Remember all of the non-matching parts. |
289 | 349 | AutoTArray<Segment, 16> nonMatching; |
290 | 349 | uint32_t i = 0; |
291 | 349 | mozilla::CheckedUint32 newLength; |
292 | 349 | while (true) |
293 | 349 | { |
294 | 349 | int32_t r = FindSubstring(this->mData + i, this->mLength - i, static_cast<const char_type*>(aTarget.Data()), aTarget.Length(), false); |
295 | 349 | int32_t until = (r == kNotFound) ? this->mLength - i : r; |
296 | 349 | nonMatching.AppendElement(Segment(i, until)); |
297 | 349 | newLength += until; |
298 | 349 | if (r == kNotFound) { |
299 | 349 | break; |
300 | 349 | } |
301 | 0 | |
302 | 0 | newLength += aNewValue.Length(); |
303 | 0 | i += r + aTarget.Length(); |
304 | 0 | if (i >= this->mLength) { |
305 | 0 | // Add an auxiliary entry at the end of the list to help as an edge case |
306 | 0 | // for the algorithms below. |
307 | 0 | nonMatching.AppendElement(Segment(this->mLength, 0)); |
308 | 0 | break; |
309 | 0 | } |
310 | 0 | } |
311 | 349 | |
312 | 349 | if (!newLength.isValid()) { |
313 | 0 | return false; |
314 | 0 | } |
315 | 349 | |
316 | 349 | // If there's only one non-matching segment, then the target string was not |
317 | 349 | // found, and there's nothing to do. |
318 | 349 | if (nonMatching.Length() == 1) { |
319 | 349 | MOZ_ASSERT(nonMatching[0].mBegin == 0 && nonMatching[0].mLength == this->mLength, |
320 | 349 | "We should have the correct non-matching segment."); |
321 | 349 | return true; |
322 | 349 | } |
323 | 0 | |
324 | 0 | // Make sure that we can mutate our buffer. |
325 | 0 | // Note that we always allocate at least an this->mLength sized buffer, because the |
326 | 0 | // rest of the algorithm relies on having access to all of the original |
327 | 0 | // string. In other words, we over-allocate in the shrinking case. |
328 | 0 | uint32_t oldLen = this->mLength; |
329 | 0 | mozilla::Result<uint32_t, nsresult> r = |
330 | 0 | this->StartBulkWriteImpl(XPCOM_MAX(oldLen, newLength.value()), oldLen); |
331 | 0 | if (r.isErr()) { |
332 | 0 | return false; |
333 | 0 | } |
334 | 0 | |
335 | 0 | if (aTarget.Length() >= aNewValue.Length()) { |
336 | 0 | // In the shrinking case, start filling the buffer from the beginning. |
337 | 0 | const uint32_t delta = (aTarget.Length() - aNewValue.Length()); |
338 | 0 | for (i = 1; i < nonMatching.Length(); ++i) { |
339 | 0 | // When we move the i'th non-matching segment into position, we need to |
340 | 0 | // account for the characters deleted by the previous |i| replacements by |
341 | 0 | // subtracting |i * delta|. |
342 | 0 | const char_type* sourceSegmentPtr = this->mData + nonMatching[i].mBegin; |
343 | 0 | char_type* destinationSegmentPtr = this->mData + nonMatching[i].mBegin - i * delta; |
344 | 0 | // Write the i'th replacement immediately before the new i'th non-matching |
345 | 0 | // segment. |
346 | 0 | char_traits::copy(destinationSegmentPtr - aNewValue.Length(), |
347 | 0 | aNewValue.Data(), aNewValue.Length()); |
348 | 0 | char_traits::move(destinationSegmentPtr, sourceSegmentPtr, |
349 | 0 | nonMatching[i].mLength); |
350 | 0 | } |
351 | 0 | } else { |
352 | 0 | // In the growing case, start filling the buffer from the end. |
353 | 0 | const uint32_t delta = (aNewValue.Length() - aTarget.Length()); |
354 | 0 | for (i = nonMatching.Length() - 1; i > 0; --i) { |
355 | 0 | // When we move the i'th non-matching segment into position, we need to |
356 | 0 | // account for the characters added by the previous |i| replacements by |
357 | 0 | // adding |i * delta|. |
358 | 0 | const char_type* sourceSegmentPtr = this->mData + nonMatching[i].mBegin; |
359 | 0 | char_type* destinationSegmentPtr = this->mData + nonMatching[i].mBegin + i * delta; |
360 | 0 | char_traits::move(destinationSegmentPtr, sourceSegmentPtr, |
361 | 0 | nonMatching[i].mLength); |
362 | 0 | // Write the i'th replacement immediately before the new i'th non-matching |
363 | 0 | // segment. |
364 | 0 | char_traits::copy(destinationSegmentPtr - aNewValue.Length(), |
365 | 0 | aNewValue.Data(), aNewValue.Length()); |
366 | 0 | } |
367 | 0 | } |
368 | 0 |
|
369 | 0 | // Adjust the length and make sure the string is null terminated. |
370 | 0 | this->FinishBulkWriteImpl(newLength.value()); |
371 | 0 |
|
372 | 0 | return true; |
373 | 0 | } nsTString<char>::ReplaceSubstring(nsTString<char> const&, nsTString<char> const&, std::nothrow_t const&) Line | Count | Source | 284 | 349 | { | 285 | 349 | if (aTarget.Length() == 0) | 286 | 0 | return true; | 287 | 349 | | 288 | 349 | // Remember all of the non-matching parts. | 289 | 349 | AutoTArray<Segment, 16> nonMatching; | 290 | 349 | uint32_t i = 0; | 291 | 349 | mozilla::CheckedUint32 newLength; | 292 | 349 | while (true) | 293 | 349 | { | 294 | 349 | int32_t r = FindSubstring(this->mData + i, this->mLength - i, static_cast<const char_type*>(aTarget.Data()), aTarget.Length(), false); | 295 | 349 | int32_t until = (r == kNotFound) ? this->mLength - i : r; | 296 | 349 | nonMatching.AppendElement(Segment(i, until)); | 297 | 349 | newLength += until; | 298 | 349 | if (r == kNotFound) { | 299 | 349 | break; | 300 | 349 | } | 301 | 0 | | 302 | 0 | newLength += aNewValue.Length(); | 303 | 0 | i += r + aTarget.Length(); | 304 | 0 | if (i >= this->mLength) { | 305 | 0 | // Add an auxiliary entry at the end of the list to help as an edge case | 306 | 0 | // for the algorithms below. | 307 | 0 | nonMatching.AppendElement(Segment(this->mLength, 0)); | 308 | 0 | break; | 309 | 0 | } | 310 | 0 | } | 311 | 349 | | 312 | 349 | if (!newLength.isValid()) { | 313 | 0 | return false; | 314 | 0 | } | 315 | 349 | | 316 | 349 | // If there's only one non-matching segment, then the target string was not | 317 | 349 | // found, and there's nothing to do. | 318 | 349 | if (nonMatching.Length() == 1) { | 319 | 349 | MOZ_ASSERT(nonMatching[0].mBegin == 0 && nonMatching[0].mLength == this->mLength, | 320 | 349 | "We should have the correct non-matching segment."); | 321 | 349 | return true; | 322 | 349 | } | 323 | 0 | | 324 | 0 | // Make sure that we can mutate our buffer. | 325 | 0 | // Note that we always allocate at least an this->mLength sized buffer, because the | 326 | 0 | // rest of the algorithm relies on having access to all of the original | 327 | 0 | // string. In other words, we over-allocate in the shrinking case. | 328 | 0 | uint32_t oldLen = this->mLength; | 329 | 0 | mozilla::Result<uint32_t, nsresult> r = | 330 | 0 | this->StartBulkWriteImpl(XPCOM_MAX(oldLen, newLength.value()), oldLen); | 331 | 0 | if (r.isErr()) { | 332 | 0 | return false; | 333 | 0 | } | 334 | 0 | | 335 | 0 | if (aTarget.Length() >= aNewValue.Length()) { | 336 | 0 | // In the shrinking case, start filling the buffer from the beginning. | 337 | 0 | const uint32_t delta = (aTarget.Length() - aNewValue.Length()); | 338 | 0 | for (i = 1; i < nonMatching.Length(); ++i) { | 339 | 0 | // When we move the i'th non-matching segment into position, we need to | 340 | 0 | // account for the characters deleted by the previous |i| replacements by | 341 | 0 | // subtracting |i * delta|. | 342 | 0 | const char_type* sourceSegmentPtr = this->mData + nonMatching[i].mBegin; | 343 | 0 | char_type* destinationSegmentPtr = this->mData + nonMatching[i].mBegin - i * delta; | 344 | 0 | // Write the i'th replacement immediately before the new i'th non-matching | 345 | 0 | // segment. | 346 | 0 | char_traits::copy(destinationSegmentPtr - aNewValue.Length(), | 347 | 0 | aNewValue.Data(), aNewValue.Length()); | 348 | 0 | char_traits::move(destinationSegmentPtr, sourceSegmentPtr, | 349 | 0 | nonMatching[i].mLength); | 350 | 0 | } | 351 | 0 | } else { | 352 | 0 | // In the growing case, start filling the buffer from the end. | 353 | 0 | const uint32_t delta = (aNewValue.Length() - aTarget.Length()); | 354 | 0 | for (i = nonMatching.Length() - 1; i > 0; --i) { | 355 | 0 | // When we move the i'th non-matching segment into position, we need to | 356 | 0 | // account for the characters added by the previous |i| replacements by | 357 | 0 | // adding |i * delta|. | 358 | 0 | const char_type* sourceSegmentPtr = this->mData + nonMatching[i].mBegin; | 359 | 0 | char_type* destinationSegmentPtr = this->mData + nonMatching[i].mBegin + i * delta; | 360 | 0 | char_traits::move(destinationSegmentPtr, sourceSegmentPtr, | 361 | 0 | nonMatching[i].mLength); | 362 | 0 | // Write the i'th replacement immediately before the new i'th non-matching | 363 | 0 | // segment. | 364 | 0 | char_traits::copy(destinationSegmentPtr - aNewValue.Length(), | 365 | 0 | aNewValue.Data(), aNewValue.Length()); | 366 | 0 | } | 367 | 0 | } | 368 | 0 |
| 369 | 0 | // Adjust the length and make sure the string is null terminated. | 370 | 0 | this->FinishBulkWriteImpl(newLength.value()); | 371 | 0 |
| 372 | 0 | return true; | 373 | 0 | } |
Unexecuted instantiation: nsTString<char16_t>::ReplaceSubstring(nsTString<char16_t> const&, nsTString<char16_t> const&, std::nothrow_t const&) |
374 | | |
375 | | /** |
376 | | * nsTString::Trim |
377 | | */ |
378 | | |
379 | | template <typename T> |
380 | | void |
381 | | nsTString<T>::Trim(const char* aSet, bool aTrimLeading, bool aTrimTrailing, bool aIgnoreQuotes) |
382 | 1.41M | { |
383 | 1.41M | // the old implementation worried about aSet being null :-/ |
384 | 1.41M | if (!aSet) |
385 | 0 | return; |
386 | 1.41M | |
387 | 1.41M | char_type* start = this->mData; |
388 | 1.41M | char_type* end = this->mData + this->mLength; |
389 | 1.41M | |
390 | 1.41M | // skip over quotes if requested |
391 | 1.41M | if (aIgnoreQuotes && this->mLength > 2 && this->mData[0] == this->mData[this->mLength - 1] && |
392 | 1.41M | (this->mData[0] == '\'' || this->mData[0] == '"')) |
393 | 0 | { |
394 | 0 | ++start; |
395 | 0 | --end; |
396 | 0 | } |
397 | 1.41M | |
398 | 1.41M | uint32_t setLen = nsCharTraits<char>::length(aSet); |
399 | 1.41M | |
400 | 1.41M | if (aTrimLeading) |
401 | 2.33k | { |
402 | 2.33k | uint32_t cutStart = start - this->mData; |
403 | 2.33k | uint32_t cutLength = 0; |
404 | 2.33k | |
405 | 2.33k | // walk forward from start to end |
406 | 2.33k | for (; start != end; ++start, ++cutLength) |
407 | 2.33k | { |
408 | 2.33k | int32_t pos = FindChar1(aSet, setLen, 0, *start, setLen); |
409 | 2.33k | if (pos == kNotFound) |
410 | 2.33k | break; |
411 | 2.33k | } |
412 | 2.33k | |
413 | 2.33k | if (cutLength) |
414 | 0 | { |
415 | 0 | this->Cut(cutStart, cutLength); |
416 | 0 |
|
417 | 0 | // reset iterators |
418 | 0 | start = this->mData + cutStart; |
419 | 0 | end = this->mData + this->mLength - cutStart; |
420 | 0 | } |
421 | 2.33k | } |
422 | 1.41M | |
423 | 1.41M | if (aTrimTrailing) |
424 | 1.41M | { |
425 | 1.41M | uint32_t cutEnd = end - this->mData; |
426 | 1.41M | uint32_t cutLength = 0; |
427 | 1.41M | |
428 | 1.41M | // walk backward from end to start |
429 | 1.41M | --end; |
430 | 2.47M | for (; end >= start; --end, ++cutLength) |
431 | 2.47M | { |
432 | 2.47M | int32_t pos = FindChar1(aSet, setLen, 0, *end, setLen); |
433 | 2.47M | if (pos == kNotFound) |
434 | 2.47M | break; |
435 | 2.47M | } |
436 | 1.41M | |
437 | 1.41M | if (cutLength) |
438 | 1.06M | this->Cut(cutEnd - cutLength, cutLength); |
439 | 1.41M | } |
440 | 1.41M | } nsTString<char>::Trim(char const*, bool, bool, bool) Line | Count | Source | 382 | 2.33k | { | 383 | 2.33k | // the old implementation worried about aSet being null :-/ | 384 | 2.33k | if (!aSet) | 385 | 0 | return; | 386 | 2.33k | | 387 | 2.33k | char_type* start = this->mData; | 388 | 2.33k | char_type* end = this->mData + this->mLength; | 389 | 2.33k | | 390 | 2.33k | // skip over quotes if requested | 391 | 2.33k | if (aIgnoreQuotes && this->mLength > 2 && this->mData[0] == this->mData[this->mLength - 1] && | 392 | 2.33k | (this->mData[0] == '\'' || this->mData[0] == '"')) | 393 | 0 | { | 394 | 0 | ++start; | 395 | 0 | --end; | 396 | 0 | } | 397 | 2.33k | | 398 | 2.33k | uint32_t setLen = nsCharTraits<char>::length(aSet); | 399 | 2.33k | | 400 | 2.33k | if (aTrimLeading) | 401 | 2.33k | { | 402 | 2.33k | uint32_t cutStart = start - this->mData; | 403 | 2.33k | uint32_t cutLength = 0; | 404 | 2.33k | | 405 | 2.33k | // walk forward from start to end | 406 | 2.33k | for (; start != end; ++start, ++cutLength) | 407 | 2.33k | { | 408 | 2.33k | int32_t pos = FindChar1(aSet, setLen, 0, *start, setLen); | 409 | 2.33k | if (pos == kNotFound) | 410 | 2.33k | break; | 411 | 2.33k | } | 412 | 2.33k | | 413 | 2.33k | if (cutLength) | 414 | 0 | { | 415 | 0 | this->Cut(cutStart, cutLength); | 416 | 0 |
| 417 | 0 | // reset iterators | 418 | 0 | start = this->mData + cutStart; | 419 | 0 | end = this->mData + this->mLength - cutStart; | 420 | 0 | } | 421 | 2.33k | } | 422 | 2.33k | | 423 | 2.33k | if (aTrimTrailing) | 424 | 2.33k | { | 425 | 2.33k | uint32_t cutEnd = end - this->mData; | 426 | 2.33k | uint32_t cutLength = 0; | 427 | 2.33k | | 428 | 2.33k | // walk backward from end to start | 429 | 2.33k | --end; | 430 | 2.33k | for (; end >= start; --end, ++cutLength) | 431 | 2.33k | { | 432 | 2.33k | int32_t pos = FindChar1(aSet, setLen, 0, *end, setLen); | 433 | 2.33k | if (pos == kNotFound) | 434 | 2.33k | break; | 435 | 2.33k | } | 436 | 2.33k | | 437 | 2.33k | if (cutLength) | 438 | 6 | this->Cut(cutEnd - cutLength, cutLength); | 439 | 2.33k | } | 440 | 2.33k | } |
nsTString<char16_t>::Trim(char const*, bool, bool, bool) Line | Count | Source | 382 | 1.41M | { | 383 | 1.41M | // the old implementation worried about aSet being null :-/ | 384 | 1.41M | if (!aSet) | 385 | 0 | return; | 386 | 1.41M | | 387 | 1.41M | char_type* start = this->mData; | 388 | 1.41M | char_type* end = this->mData + this->mLength; | 389 | 1.41M | | 390 | 1.41M | // skip over quotes if requested | 391 | 1.41M | if (aIgnoreQuotes && this->mLength > 2 && this->mData[0] == this->mData[this->mLength - 1] && | 392 | 1.41M | (this->mData[0] == '\'' || this->mData[0] == '"')) | 393 | 0 | { | 394 | 0 | ++start; | 395 | 0 | --end; | 396 | 0 | } | 397 | 1.41M | | 398 | 1.41M | uint32_t setLen = nsCharTraits<char>::length(aSet); | 399 | 1.41M | | 400 | 1.41M | if (aTrimLeading) | 401 | 0 | { | 402 | 0 | uint32_t cutStart = start - this->mData; | 403 | 0 | uint32_t cutLength = 0; | 404 | 0 |
| 405 | 0 | // walk forward from start to end | 406 | 0 | for (; start != end; ++start, ++cutLength) | 407 | 0 | { | 408 | 0 | int32_t pos = FindChar1(aSet, setLen, 0, *start, setLen); | 409 | 0 | if (pos == kNotFound) | 410 | 0 | break; | 411 | 0 | } | 412 | 0 |
| 413 | 0 | if (cutLength) | 414 | 0 | { | 415 | 0 | this->Cut(cutStart, cutLength); | 416 | 0 |
| 417 | 0 | // reset iterators | 418 | 0 | start = this->mData + cutStart; | 419 | 0 | end = this->mData + this->mLength - cutStart; | 420 | 0 | } | 421 | 0 | } | 422 | 1.41M | | 423 | 1.41M | if (aTrimTrailing) | 424 | 1.41M | { | 425 | 1.41M | uint32_t cutEnd = end - this->mData; | 426 | 1.41M | uint32_t cutLength = 0; | 427 | 1.41M | | 428 | 1.41M | // walk backward from end to start | 429 | 1.41M | --end; | 430 | 2.47M | for (; end >= start; --end, ++cutLength) | 431 | 2.47M | { | 432 | 2.47M | int32_t pos = FindChar1(aSet, setLen, 0, *end, setLen); | 433 | 2.47M | if (pos == kNotFound) | 434 | 2.47M | break; | 435 | 2.47M | } | 436 | 1.41M | | 437 | 1.41M | if (cutLength) | 438 | 1.06M | this->Cut(cutEnd - cutLength, cutLength); | 439 | 1.41M | } | 440 | 1.41M | } |
|
441 | | |
442 | | |
443 | | /** |
444 | | * nsTString::CompressWhitespace. |
445 | | */ |
446 | | |
447 | | template <typename T> |
448 | | void |
449 | | nsTString<T>::CompressWhitespace(bool aTrimLeading, bool aTrimTrailing) |
450 | 24 | { |
451 | 24 | // Quick exit |
452 | 24 | if (this->mLength == 0) { |
453 | 9 | return; |
454 | 9 | } |
455 | 15 | |
456 | 15 | if (!this->EnsureMutable()) |
457 | 0 | this->AllocFailed(this->mLength); |
458 | 15 | |
459 | 15 | const ASCIIMaskArray& mask = mozilla::ASCIIMask::MaskWhitespace(); |
460 | 15 | |
461 | 15 | char_type* to = this->mData; |
462 | 15 | char_type* from = this->mData; |
463 | 15 | char_type* end = this->mData + this->mLength; |
464 | 15 | |
465 | 15 | // Compresses runs of whitespace down to a normal space ' ' and convert |
466 | 15 | // any whitespace to a normal space. This assumes that whitespace is |
467 | 15 | // all standard 7-bit ASCII. |
468 | 15 | bool skipWS = aTrimLeading; |
469 | 402 | while (from < end) { |
470 | 387 | uint32_t theChar = *from++; |
471 | 387 | if (mozilla::ASCIIMask::IsMasked(mask, theChar)) { |
472 | 3 | if (!skipWS) { |
473 | 3 | *to++ = ' '; |
474 | 3 | skipWS = true; |
475 | 3 | } |
476 | 384 | } else { |
477 | 384 | *to++ = theChar; |
478 | 384 | skipWS = false; |
479 | 384 | } |
480 | 387 | } |
481 | 15 | |
482 | 15 | // If we need to trim the trailing whitespace, back up one character. |
483 | 15 | if (aTrimTrailing && skipWS && to > this->mData) { |
484 | 0 | to--; |
485 | 0 | } |
486 | 15 | |
487 | 15 | *to = char_type(0); // add the null |
488 | 15 | this->mLength = to - this->mData; |
489 | 15 | } nsTString<char>::CompressWhitespace(bool, bool) Line | Count | Source | 450 | 24 | { | 451 | 24 | // Quick exit | 452 | 24 | if (this->mLength == 0) { | 453 | 9 | return; | 454 | 9 | } | 455 | 15 | | 456 | 15 | if (!this->EnsureMutable()) | 457 | 0 | this->AllocFailed(this->mLength); | 458 | 15 | | 459 | 15 | const ASCIIMaskArray& mask = mozilla::ASCIIMask::MaskWhitespace(); | 460 | 15 | | 461 | 15 | char_type* to = this->mData; | 462 | 15 | char_type* from = this->mData; | 463 | 15 | char_type* end = this->mData + this->mLength; | 464 | 15 | | 465 | 15 | // Compresses runs of whitespace down to a normal space ' ' and convert | 466 | 15 | // any whitespace to a normal space. This assumes that whitespace is | 467 | 15 | // all standard 7-bit ASCII. | 468 | 15 | bool skipWS = aTrimLeading; | 469 | 402 | while (from < end) { | 470 | 387 | uint32_t theChar = *from++; | 471 | 387 | if (mozilla::ASCIIMask::IsMasked(mask, theChar)) { | 472 | 3 | if (!skipWS) { | 473 | 3 | *to++ = ' '; | 474 | 3 | skipWS = true; | 475 | 3 | } | 476 | 384 | } else { | 477 | 384 | *to++ = theChar; | 478 | 384 | skipWS = false; | 479 | 384 | } | 480 | 387 | } | 481 | 15 | | 482 | 15 | // If we need to trim the trailing whitespace, back up one character. | 483 | 15 | if (aTrimTrailing && skipWS && to > this->mData) { | 484 | 0 | to--; | 485 | 0 | } | 486 | 15 | | 487 | 15 | *to = char_type(0); // add the null | 488 | 15 | this->mLength = to - this->mData; | 489 | 15 | } |
Unexecuted instantiation: nsTString<char16_t>::CompressWhitespace(bool, bool) |