/src/mozilla-central/xpcom/string/nsTSubstring.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 "double-conversion/double-conversion.h" |
8 | | #include "mozilla/CheckedInt.h" |
9 | | #include "mozilla/MathAlgorithms.h" |
10 | | #include "mozilla/MemoryReporting.h" |
11 | | #include "mozilla/Printf.h" |
12 | | |
13 | | #include "nsASCIIMask.h" |
14 | | |
15 | | // It's not worthwhile to reallocate the buffer and memcpy the |
16 | | // contents over when the size difference isn't large. With |
17 | | // power-of-two allocation buckets and 64 as the typical inline |
18 | | // capacity, considering that above 1000 there performance aspects |
19 | | // of realloc and memcpy seem to be absorbed, relative to the old |
20 | | // code, by the performance benefits of the new code being exact, |
21 | | // we need to choose which transitions of 256 to 128, 512 to 256 |
22 | | // and 1024 to 512 to allow. As a guess, let's pick the middle |
23 | | // one as the the largest potential transition that we forgo. So |
24 | | // we'll shrink from 1024 bucket to 512 bucket but not from 512 |
25 | | // bucket to 256 bucket. We'll decide by comparing the difference |
26 | | // of capacities. As bucket differences, the differences are 256 |
27 | | // and 512. Since the capacities have various overheads, we |
28 | | // can't compare with 256 or 512 exactly but it's easier to |
29 | | // compare to some number that's between the two, so it's |
30 | | // far away from either to ignore the overheads. |
31 | | const uint32_t kNsStringBufferShrinkingThreshold = 384; |
32 | | |
33 | | using double_conversion::DoubleToStringConverter; |
34 | | |
35 | | template <typename T> |
36 | | const typename nsTSubstring<T>::size_type nsTSubstring<T>::kMaxCapacity = |
37 | | (nsTSubstring<T>::size_type(-1) / |
38 | | 2 - sizeof(nsStringBuffer)) / |
39 | | sizeof(nsTSubstring<T>::char_type) - 2; |
40 | | |
41 | | #ifdef XPCOM_STRING_CONSTRUCTOR_OUT_OF_LINE |
42 | | template <typename T> |
43 | | nsTSubstring<T>::nsTSubstring(char_type* aData, size_type aLength, |
44 | | DataFlags aDataFlags, |
45 | | ClassFlags aClassFlags) |
46 | | : ::mozilla::detail::nsTStringRepr<T>(aData, aLength, aDataFlags, aClassFlags) |
47 | | { |
48 | | AssertValid(); |
49 | | MOZ_RELEASE_ASSERT(CheckCapacity(aLength), "String is too large."); |
50 | | |
51 | | if (aDataFlags & DataFlags::OWNED) { |
52 | | STRING_STAT_INCREMENT(Adopt); |
53 | | MOZ_LOG_CTOR(this->mData, "StringAdopt", 1); |
54 | | } |
55 | | } |
56 | | #endif /* XPCOM_STRING_CONSTRUCTOR_OUT_OF_LINE */ |
57 | | |
58 | | /** |
59 | | * helper function for down-casting a nsTSubstring to an nsTAutoString. |
60 | | */ |
61 | | template <typename T> |
62 | | inline const nsTAutoString<T>* |
63 | | AsAutoString(const nsTSubstring<T>* aStr) |
64 | 119M | { |
65 | 119M | return static_cast<const nsTAutoString<T>*>(aStr); |
66 | 119M | } nsTAutoStringN<char, 64ul> const* AsAutoString<char>(nsTSubstring<char> const*) Line | Count | Source | 64 | 111M | { | 65 | 111M | return static_cast<const nsTAutoString<T>*>(aStr); | 66 | 111M | } |
nsTAutoStringN<char16_t, 64ul> const* AsAutoString<char16_t>(nsTSubstring<char16_t> const*) Line | Count | Source | 64 | 8.01M | { | 65 | 8.01M | return static_cast<const nsTAutoString<T>*>(aStr); | 66 | 8.01M | } |
|
67 | | |
68 | | template<typename T> |
69 | | mozilla::BulkWriteHandle<T> |
70 | | nsTSubstring<T>::BulkWrite(size_type aCapacity, |
71 | | size_type aPrefixToPreserve, |
72 | | bool aAllowShrinking, |
73 | | nsresult& aRv) |
74 | 0 | { |
75 | 0 | auto r = StartBulkWriteImpl(aCapacity, |
76 | 0 | aPrefixToPreserve, |
77 | 0 | aAllowShrinking); |
78 | 0 | if (MOZ_UNLIKELY(r.isErr())) { |
79 | 0 | aRv = r.unwrapErr(); |
80 | 0 | return mozilla::BulkWriteHandle<T>(nullptr, 0); |
81 | 0 | } |
82 | 0 | aRv = NS_OK; |
83 | 0 | return mozilla::BulkWriteHandle<T>(this, r.unwrap()); |
84 | 0 | } Unexecuted instantiation: nsTSubstring<char>::BulkWrite(unsigned int, unsigned int, bool, nsresult&) Unexecuted instantiation: nsTSubstring<char16_t>::BulkWrite(unsigned int, unsigned int, bool, nsresult&) |
85 | | |
86 | | |
87 | | template<typename T> |
88 | | mozilla::Result<uint32_t, nsresult> |
89 | | nsTSubstring<T>::StartBulkWriteImpl(size_type aCapacity, |
90 | | size_type aPrefixToPreserve, |
91 | | bool aAllowShrinking, |
92 | | size_type aSuffixLength, |
93 | | size_type aOldSuffixStart, |
94 | | size_type aNewSuffixStart) |
95 | 95.0M | { |
96 | 95.0M | // Note! Capacity does not include room for the terminating null char. |
97 | 95.0M | |
98 | 95.0M | MOZ_ASSERT(aPrefixToPreserve <= aCapacity, |
99 | 95.0M | "Requested preservation of an overlong prefix."); |
100 | 95.0M | MOZ_ASSERT(aNewSuffixStart + aSuffixLength <= aCapacity, |
101 | 95.0M | "Requesed move of suffix to out-of-bounds location."); |
102 | 95.0M | // Can't assert aOldSuffixStart, because mLength may not be valid anymore, |
103 | 95.0M | // since this method allows itself to be called more than once. |
104 | 95.0M | |
105 | 95.0M | // If zero capacity is requested, set the string to the special empty |
106 | 95.0M | // string. |
107 | 95.0M | if (MOZ_UNLIKELY(!aCapacity)) { |
108 | 25.2k | ::ReleaseData(this->mData, this->mDataFlags); |
109 | 25.2k | SetToEmptyBuffer(); |
110 | 25.2k | return 0; |
111 | 25.2k | } |
112 | 95.0M | |
113 | 95.0M | // Note! Capacity() returns 0 when the string is immutable. |
114 | 95.0M | const size_type curCapacity = Capacity(); |
115 | 95.0M | |
116 | 95.0M | bool shrinking = false; |
117 | 95.0M | |
118 | 95.0M | // We've established that aCapacity > 0. |
119 | 95.0M | // |curCapacity == 0| means that the buffer is immutable or 0-sized, so we |
120 | 95.0M | // need to allocate a new buffer. We cannot use the existing buffer even |
121 | 95.0M | // though it might be large enough. |
122 | 95.0M | |
123 | 95.0M | if (aCapacity <= curCapacity) { |
124 | 65.8M | if (aAllowShrinking) { |
125 | 23.4M | shrinking = true; |
126 | 42.4M | } else { |
127 | 42.4M | char_traits::move(this->mData + aNewSuffixStart, |
128 | 42.4M | this->mData + aOldSuffixStart, |
129 | 42.4M | aSuffixLength); |
130 | 42.4M | if (aSuffixLength) { |
131 | 3.18k | char_traits::uninitialize( |
132 | 3.18k | this->mData + aPrefixToPreserve, |
133 | 3.18k | XPCOM_MIN(size_t(aNewSuffixStart - aPrefixToPreserve), |
134 | 3.18k | kNsStringBufferMaxPoison)); |
135 | 3.18k | char_traits::uninitialize( |
136 | 3.18k | this->mData + aNewSuffixStart + aSuffixLength, |
137 | 3.18k | XPCOM_MIN(size_t(curCapacity + 1 - aNewSuffixStart - aSuffixLength), |
138 | 3.18k | kNsStringBufferMaxPoison)); |
139 | 42.4M | } else { |
140 | 42.4M | char_traits::uninitialize( |
141 | 42.4M | this->mData + aPrefixToPreserve, |
142 | 42.4M | XPCOM_MIN(size_t(curCapacity + 1 - aPrefixToPreserve), |
143 | 42.4M | kNsStringBufferMaxPoison)); |
144 | 42.4M | } |
145 | 42.4M | return curCapacity; |
146 | 42.4M | } |
147 | 52.6M | } |
148 | 52.6M | |
149 | 52.6M | char_type* oldData = this->mData; |
150 | 52.6M | DataFlags oldFlags = this->mDataFlags; |
151 | 52.6M | |
152 | 52.6M | char_type* newData; |
153 | 52.6M | DataFlags newDataFlags; |
154 | 52.6M | size_type newCapacity; |
155 | 52.6M | |
156 | 52.6M | // If this is an nsTAutoStringN, it's possible that we can use the inline |
157 | 52.6M | // buffer. |
158 | 52.6M | if ((this->mClassFlags & ClassFlags::INLINE) && |
159 | 52.6M | (aCapacity <= AsAutoString(this)->mInlineCapacity)) { |
160 | 29.2M | newCapacity = AsAutoString(this)->mInlineCapacity; |
161 | 29.2M | newData = (char_type*)AsAutoString(this)->mStorage; |
162 | 29.2M | newDataFlags = DataFlags::TERMINATED | DataFlags::INLINE; |
163 | 29.2M | } else { |
164 | 23.3M | // If |aCapacity > kMaxCapacity|, then our doubling algorithm may not be |
165 | 23.3M | // able to allocate it. Just bail out in cases like that. We don't want |
166 | 23.3M | // to be allocating 2GB+ strings anyway. |
167 | 23.3M | static_assert((sizeof(nsStringBuffer) & 0x1) == 0, |
168 | 23.3M | "bad size for nsStringBuffer"); |
169 | 23.3M | if (MOZ_UNLIKELY(!CheckCapacity(aCapacity))) { |
170 | 0 | return mozilla::Err(NS_ERROR_OUT_OF_MEMORY); |
171 | 0 | } |
172 | 23.3M | |
173 | 23.3M | // We increase our capacity so that the allocated buffer grows |
174 | 23.3M | // exponentially, which gives us amortized O(1) appending. Below the |
175 | 23.3M | // threshold, we use powers-of-two. Above the threshold, we grow by at |
176 | 23.3M | // least 1.125, rounding up to the nearest MiB. |
177 | 23.3M | const size_type slowGrowthThreshold = 8 * 1024 * 1024; |
178 | 23.3M | |
179 | 23.3M | // nsStringBuffer allocates sizeof(nsStringBuffer) + passed size, and |
180 | 23.3M | // storageSize below wants extra 1 * sizeof(char_type). |
181 | 23.3M | const size_type neededExtraSpace = |
182 | 23.3M | sizeof(nsStringBuffer) / sizeof(char_type) + 1; |
183 | 23.3M | |
184 | 23.3M | size_type temp; |
185 | 23.3M | if (aCapacity >= slowGrowthThreshold) { |
186 | 0 | size_type minNewCapacity = curCapacity + (curCapacity >> 3); // multiply by 1.125 |
187 | 0 | temp = XPCOM_MAX(aCapacity, minNewCapacity) + neededExtraSpace; |
188 | 0 |
|
189 | 0 | // Round up to the next multiple of MiB, but ensure the expected |
190 | 0 | // capacity doesn't include the extra space required by nsStringBuffer |
191 | 0 | // and null-termination. |
192 | 0 | const size_t MiB = 1 << 20; |
193 | 0 | temp = (MiB * ((temp + MiB - 1) / MiB)) - neededExtraSpace; |
194 | 23.3M | } else { |
195 | 23.3M | // Round up to the next power of two. |
196 | 23.3M | temp = |
197 | 23.3M | mozilla::RoundUpPow2(aCapacity + neededExtraSpace) - neededExtraSpace; |
198 | 23.3M | } |
199 | 23.3M | |
200 | 23.3M | newCapacity = XPCOM_MIN(temp, kMaxCapacity); |
201 | 23.3M | MOZ_ASSERT(newCapacity >= aCapacity, |
202 | 23.3M | "should have hit the early return at the top"); |
203 | 23.3M | // Avoid shrinking if the new buffer size is close to the old. Note that |
204 | 23.3M | // unsigned underflow is defined behavior. |
205 | 23.3M | if ((curCapacity - newCapacity) <= kNsStringBufferShrinkingThreshold && |
206 | 23.3M | (this->mDataFlags & DataFlags::REFCOUNTED)) { |
207 | 1.11M | MOZ_ASSERT(aAllowShrinking, "How come we didn't return earlier?"); |
208 | 1.11M | // We're already close enough to the right size. |
209 | 1.11M | newData = oldData; |
210 | 1.11M | newCapacity = curCapacity; |
211 | 22.2M | } else { |
212 | 22.2M | size_type storageSize = (newCapacity + 1) * sizeof(char_type); |
213 | 22.2M | // Since we allocate only by powers of 2 we always fit into a full mozjemalloc |
214 | 22.2M | // bucket, it's not useful to use realloc, which may spend time uselessly |
215 | 22.2M | // copying too much. |
216 | 22.2M | nsStringBuffer* newHdr = nsStringBuffer::Alloc(storageSize).take(); |
217 | 22.2M | if (newHdr) { |
218 | 22.2M | newData = (char_type*)newHdr->Data(); |
219 | 22.2M | } else if (shrinking) { |
220 | 0 | // We're still in a consistent state. |
221 | 0 | // |
222 | 0 | // Since shrinking is just a memory footprint optimization, we |
223 | 0 | // don't propagate OOM if we tried to shrink in order to avoid |
224 | 0 | // OOM crashes from infallible callers. If we're lucky, soon enough |
225 | 0 | // a fallible caller reaches OOM and is able to deal or we end up |
226 | 0 | // disposing of this string before reaching OOM again. |
227 | 0 | newData = oldData; |
228 | 0 | newCapacity = curCapacity; |
229 | 0 | } else { |
230 | 0 | return mozilla::Err(NS_ERROR_OUT_OF_MEMORY); |
231 | 0 | } |
232 | 23.3M | } |
233 | 23.3M | newDataFlags = DataFlags::TERMINATED | DataFlags::REFCOUNTED; |
234 | 23.3M | } |
235 | 52.6M | |
236 | 52.6M | this->mData = newData; |
237 | 52.6M | this->mDataFlags = newDataFlags; |
238 | 52.6M | |
239 | 52.6M | if (oldData == newData) { |
240 | 23.4M | char_traits::move( |
241 | 23.4M | newData + aNewSuffixStart, oldData + aOldSuffixStart, aSuffixLength); |
242 | 23.4M | if (aSuffixLength) { |
243 | 0 | char_traits::uninitialize( |
244 | 0 | this->mData + aPrefixToPreserve, |
245 | 0 | XPCOM_MIN(size_t(aNewSuffixStart - aPrefixToPreserve), |
246 | 0 | kNsStringBufferMaxPoison)); |
247 | 0 | char_traits::uninitialize( |
248 | 0 | this->mData + aNewSuffixStart + aSuffixLength, |
249 | 0 | XPCOM_MIN(size_t(newCapacity + 1 - aNewSuffixStart - aSuffixLength), |
250 | 0 | kNsStringBufferMaxPoison)); |
251 | 23.4M | } else { |
252 | 23.4M | char_traits::uninitialize( |
253 | 23.4M | this->mData + aPrefixToPreserve, |
254 | 23.4M | XPCOM_MIN(size_t(newCapacity + 1 - aPrefixToPreserve), |
255 | 23.4M | kNsStringBufferMaxPoison)); |
256 | 23.4M | } |
257 | 29.1M | } else { |
258 | 29.1M | char_traits::copy(newData, oldData, aPrefixToPreserve); |
259 | 29.1M | char_traits::copy( |
260 | 29.1M | newData + aNewSuffixStart, oldData + aOldSuffixStart, aSuffixLength); |
261 | 29.1M | ::ReleaseData(oldData, oldFlags); |
262 | 29.1M | } |
263 | 52.6M | |
264 | 52.6M | return newCapacity; |
265 | 52.6M | } nsTSubstring<char>::StartBulkWriteImpl(unsigned int, unsigned int, bool, unsigned int, unsigned int, unsigned int) Line | Count | Source | 95 | 46.1M | { | 96 | 46.1M | // Note! Capacity does not include room for the terminating null char. | 97 | 46.1M | | 98 | 46.1M | MOZ_ASSERT(aPrefixToPreserve <= aCapacity, | 99 | 46.1M | "Requested preservation of an overlong prefix."); | 100 | 46.1M | MOZ_ASSERT(aNewSuffixStart + aSuffixLength <= aCapacity, | 101 | 46.1M | "Requesed move of suffix to out-of-bounds location."); | 102 | 46.1M | // Can't assert aOldSuffixStart, because mLength may not be valid anymore, | 103 | 46.1M | // since this method allows itself to be called more than once. | 104 | 46.1M | | 105 | 46.1M | // If zero capacity is requested, set the string to the special empty | 106 | 46.1M | // string. | 107 | 46.1M | if (MOZ_UNLIKELY(!aCapacity)) { | 108 | 25.2k | ::ReleaseData(this->mData, this->mDataFlags); | 109 | 25.2k | SetToEmptyBuffer(); | 110 | 25.2k | return 0; | 111 | 25.2k | } | 112 | 46.1M | | 113 | 46.1M | // Note! Capacity() returns 0 when the string is immutable. | 114 | 46.1M | const size_type curCapacity = Capacity(); | 115 | 46.1M | | 116 | 46.1M | bool shrinking = false; | 117 | 46.1M | | 118 | 46.1M | // We've established that aCapacity > 0. | 119 | 46.1M | // |curCapacity == 0| means that the buffer is immutable or 0-sized, so we | 120 | 46.1M | // need to allocate a new buffer. We cannot use the existing buffer even | 121 | 46.1M | // though it might be large enough. | 122 | 46.1M | | 123 | 46.1M | if (aCapacity <= curCapacity) { | 124 | 29.4M | if (aAllowShrinking) { | 125 | 21.7M | shrinking = true; | 126 | 21.7M | } else { | 127 | 7.69M | char_traits::move(this->mData + aNewSuffixStart, | 128 | 7.69M | this->mData + aOldSuffixStart, | 129 | 7.69M | aSuffixLength); | 130 | 7.69M | if (aSuffixLength) { | 131 | 3.16k | char_traits::uninitialize( | 132 | 3.16k | this->mData + aPrefixToPreserve, | 133 | 3.16k | XPCOM_MIN(size_t(aNewSuffixStart - aPrefixToPreserve), | 134 | 3.16k | kNsStringBufferMaxPoison)); | 135 | 3.16k | char_traits::uninitialize( | 136 | 3.16k | this->mData + aNewSuffixStart + aSuffixLength, | 137 | 3.16k | XPCOM_MIN(size_t(curCapacity + 1 - aNewSuffixStart - aSuffixLength), | 138 | 3.16k | kNsStringBufferMaxPoison)); | 139 | 7.68M | } else { | 140 | 7.68M | char_traits::uninitialize( | 141 | 7.68M | this->mData + aPrefixToPreserve, | 142 | 7.68M | XPCOM_MIN(size_t(curCapacity + 1 - aPrefixToPreserve), | 143 | 7.68M | kNsStringBufferMaxPoison)); | 144 | 7.68M | } | 145 | 7.69M | return curCapacity; | 146 | 7.69M | } | 147 | 38.4M | } | 148 | 38.4M | | 149 | 38.4M | char_type* oldData = this->mData; | 150 | 38.4M | DataFlags oldFlags = this->mDataFlags; | 151 | 38.4M | | 152 | 38.4M | char_type* newData; | 153 | 38.4M | DataFlags newDataFlags; | 154 | 38.4M | size_type newCapacity; | 155 | 38.4M | | 156 | 38.4M | // If this is an nsTAutoStringN, it's possible that we can use the inline | 157 | 38.4M | // buffer. | 158 | 38.4M | if ((this->mClassFlags & ClassFlags::INLINE) && | 159 | 38.4M | (aCapacity <= AsAutoString(this)->mInlineCapacity)) { | 160 | 27.5M | newCapacity = AsAutoString(this)->mInlineCapacity; | 161 | 27.5M | newData = (char_type*)AsAutoString(this)->mStorage; | 162 | 27.5M | newDataFlags = DataFlags::TERMINATED | DataFlags::INLINE; | 163 | 27.5M | } else { | 164 | 10.9M | // If |aCapacity > kMaxCapacity|, then our doubling algorithm may not be | 165 | 10.9M | // able to allocate it. Just bail out in cases like that. We don't want | 166 | 10.9M | // to be allocating 2GB+ strings anyway. | 167 | 10.9M | static_assert((sizeof(nsStringBuffer) & 0x1) == 0, | 168 | 10.9M | "bad size for nsStringBuffer"); | 169 | 10.9M | if (MOZ_UNLIKELY(!CheckCapacity(aCapacity))) { | 170 | 0 | return mozilla::Err(NS_ERROR_OUT_OF_MEMORY); | 171 | 0 | } | 172 | 10.9M | | 173 | 10.9M | // We increase our capacity so that the allocated buffer grows | 174 | 10.9M | // exponentially, which gives us amortized O(1) appending. Below the | 175 | 10.9M | // threshold, we use powers-of-two. Above the threshold, we grow by at | 176 | 10.9M | // least 1.125, rounding up to the nearest MiB. | 177 | 10.9M | const size_type slowGrowthThreshold = 8 * 1024 * 1024; | 178 | 10.9M | | 179 | 10.9M | // nsStringBuffer allocates sizeof(nsStringBuffer) + passed size, and | 180 | 10.9M | // storageSize below wants extra 1 * sizeof(char_type). | 181 | 10.9M | const size_type neededExtraSpace = | 182 | 10.9M | sizeof(nsStringBuffer) / sizeof(char_type) + 1; | 183 | 10.9M | | 184 | 10.9M | size_type temp; | 185 | 10.9M | if (aCapacity >= slowGrowthThreshold) { | 186 | 0 | size_type minNewCapacity = curCapacity + (curCapacity >> 3); // multiply by 1.125 | 187 | 0 | temp = XPCOM_MAX(aCapacity, minNewCapacity) + neededExtraSpace; | 188 | 0 |
| 189 | 0 | // Round up to the next multiple of MiB, but ensure the expected | 190 | 0 | // capacity doesn't include the extra space required by nsStringBuffer | 191 | 0 | // and null-termination. | 192 | 0 | const size_t MiB = 1 << 20; | 193 | 0 | temp = (MiB * ((temp + MiB - 1) / MiB)) - neededExtraSpace; | 194 | 10.9M | } else { | 195 | 10.9M | // Round up to the next power of two. | 196 | 10.9M | temp = | 197 | 10.9M | mozilla::RoundUpPow2(aCapacity + neededExtraSpace) - neededExtraSpace; | 198 | 10.9M | } | 199 | 10.9M | | 200 | 10.9M | newCapacity = XPCOM_MIN(temp, kMaxCapacity); | 201 | 10.9M | MOZ_ASSERT(newCapacity >= aCapacity, | 202 | 10.9M | "should have hit the early return at the top"); | 203 | 10.9M | // Avoid shrinking if the new buffer size is close to the old. Note that | 204 | 10.9M | // unsigned underflow is defined behavior. | 205 | 10.9M | if ((curCapacity - newCapacity) <= kNsStringBufferShrinkingThreshold && | 206 | 10.9M | (this->mDataFlags & DataFlags::REFCOUNTED)) { | 207 | 1.11M | MOZ_ASSERT(aAllowShrinking, "How come we didn't return earlier?"); | 208 | 1.11M | // We're already close enough to the right size. | 209 | 1.11M | newData = oldData; | 210 | 1.11M | newCapacity = curCapacity; | 211 | 9.82M | } else { | 212 | 9.82M | size_type storageSize = (newCapacity + 1) * sizeof(char_type); | 213 | 9.82M | // Since we allocate only by powers of 2 we always fit into a full mozjemalloc | 214 | 9.82M | // bucket, it's not useful to use realloc, which may spend time uselessly | 215 | 9.82M | // copying too much. | 216 | 9.82M | nsStringBuffer* newHdr = nsStringBuffer::Alloc(storageSize).take(); | 217 | 9.82M | if (newHdr) { | 218 | 9.82M | newData = (char_type*)newHdr->Data(); | 219 | 9.82M | } else if (shrinking) { | 220 | 0 | // We're still in a consistent state. | 221 | 0 | // | 222 | 0 | // Since shrinking is just a memory footprint optimization, we | 223 | 0 | // don't propagate OOM if we tried to shrink in order to avoid | 224 | 0 | // OOM crashes from infallible callers. If we're lucky, soon enough | 225 | 0 | // a fallible caller reaches OOM and is able to deal or we end up | 226 | 0 | // disposing of this string before reaching OOM again. | 227 | 0 | newData = oldData; | 228 | 0 | newCapacity = curCapacity; | 229 | 0 | } else { | 230 | 0 | return mozilla::Err(NS_ERROR_OUT_OF_MEMORY); | 231 | 0 | } | 232 | 10.9M | } | 233 | 10.9M | newDataFlags = DataFlags::TERMINATED | DataFlags::REFCOUNTED; | 234 | 10.9M | } | 235 | 38.4M | | 236 | 38.4M | this->mData = newData; | 237 | 38.4M | this->mDataFlags = newDataFlags; | 238 | 38.4M | | 239 | 38.4M | if (oldData == newData) { | 240 | 21.7M | char_traits::move( | 241 | 21.7M | newData + aNewSuffixStart, oldData + aOldSuffixStart, aSuffixLength); | 242 | 21.7M | if (aSuffixLength) { | 243 | 0 | char_traits::uninitialize( | 244 | 0 | this->mData + aPrefixToPreserve, | 245 | 0 | XPCOM_MIN(size_t(aNewSuffixStart - aPrefixToPreserve), | 246 | 0 | kNsStringBufferMaxPoison)); | 247 | 0 | char_traits::uninitialize( | 248 | 0 | this->mData + aNewSuffixStart + aSuffixLength, | 249 | 0 | XPCOM_MIN(size_t(newCapacity + 1 - aNewSuffixStart - aSuffixLength), | 250 | 0 | kNsStringBufferMaxPoison)); | 251 | 21.7M | } else { | 252 | 21.7M | char_traits::uninitialize( | 253 | 21.7M | this->mData + aPrefixToPreserve, | 254 | 21.7M | XPCOM_MIN(size_t(newCapacity + 1 - aPrefixToPreserve), | 255 | 21.7M | kNsStringBufferMaxPoison)); | 256 | 21.7M | } | 257 | 21.7M | } else { | 258 | 16.7M | char_traits::copy(newData, oldData, aPrefixToPreserve); | 259 | 16.7M | char_traits::copy( | 260 | 16.7M | newData + aNewSuffixStart, oldData + aOldSuffixStart, aSuffixLength); | 261 | 16.7M | ::ReleaseData(oldData, oldFlags); | 262 | 16.7M | } | 263 | 38.4M | | 264 | 38.4M | return newCapacity; | 265 | 38.4M | } |
nsTSubstring<char16_t>::StartBulkWriteImpl(unsigned int, unsigned int, bool, unsigned int, unsigned int, unsigned int) Line | Count | Source | 95 | 48.8M | { | 96 | 48.8M | // Note! Capacity does not include room for the terminating null char. | 97 | 48.8M | | 98 | 48.8M | MOZ_ASSERT(aPrefixToPreserve <= aCapacity, | 99 | 48.8M | "Requested preservation of an overlong prefix."); | 100 | 48.8M | MOZ_ASSERT(aNewSuffixStart + aSuffixLength <= aCapacity, | 101 | 48.8M | "Requesed move of suffix to out-of-bounds location."); | 102 | 48.8M | // Can't assert aOldSuffixStart, because mLength may not be valid anymore, | 103 | 48.8M | // since this method allows itself to be called more than once. | 104 | 48.8M | | 105 | 48.8M | // If zero capacity is requested, set the string to the special empty | 106 | 48.8M | // string. | 107 | 48.8M | if (MOZ_UNLIKELY(!aCapacity)) { | 108 | 51 | ::ReleaseData(this->mData, this->mDataFlags); | 109 | 51 | SetToEmptyBuffer(); | 110 | 51 | return 0; | 111 | 51 | } | 112 | 48.8M | | 113 | 48.8M | // Note! Capacity() returns 0 when the string is immutable. | 114 | 48.8M | const size_type curCapacity = Capacity(); | 115 | 48.8M | | 116 | 48.8M | bool shrinking = false; | 117 | 48.8M | | 118 | 48.8M | // We've established that aCapacity > 0. | 119 | 48.8M | // |curCapacity == 0| means that the buffer is immutable or 0-sized, so we | 120 | 48.8M | // need to allocate a new buffer. We cannot use the existing buffer even | 121 | 48.8M | // though it might be large enough. | 122 | 48.8M | | 123 | 48.8M | if (aCapacity <= curCapacity) { | 124 | 36.4M | if (aAllowShrinking) { | 125 | 1.70M | shrinking = true; | 126 | 34.7M | } else { | 127 | 34.7M | char_traits::move(this->mData + aNewSuffixStart, | 128 | 34.7M | this->mData + aOldSuffixStart, | 129 | 34.7M | aSuffixLength); | 130 | 34.7M | if (aSuffixLength) { | 131 | 24 | char_traits::uninitialize( | 132 | 24 | this->mData + aPrefixToPreserve, | 133 | 24 | XPCOM_MIN(size_t(aNewSuffixStart - aPrefixToPreserve), | 134 | 24 | kNsStringBufferMaxPoison)); | 135 | 24 | char_traits::uninitialize( | 136 | 24 | this->mData + aNewSuffixStart + aSuffixLength, | 137 | 24 | XPCOM_MIN(size_t(curCapacity + 1 - aNewSuffixStart - aSuffixLength), | 138 | 24 | kNsStringBufferMaxPoison)); | 139 | 34.7M | } else { | 140 | 34.7M | char_traits::uninitialize( | 141 | 34.7M | this->mData + aPrefixToPreserve, | 142 | 34.7M | XPCOM_MIN(size_t(curCapacity + 1 - aPrefixToPreserve), | 143 | 34.7M | kNsStringBufferMaxPoison)); | 144 | 34.7M | } | 145 | 34.7M | return curCapacity; | 146 | 34.7M | } | 147 | 14.1M | } | 148 | 14.1M | | 149 | 14.1M | char_type* oldData = this->mData; | 150 | 14.1M | DataFlags oldFlags = this->mDataFlags; | 151 | 14.1M | | 152 | 14.1M | char_type* newData; | 153 | 14.1M | DataFlags newDataFlags; | 154 | 14.1M | size_type newCapacity; | 155 | 14.1M | | 156 | 14.1M | // If this is an nsTAutoStringN, it's possible that we can use the inline | 157 | 14.1M | // buffer. | 158 | 14.1M | if ((this->mClassFlags & ClassFlags::INLINE) && | 159 | 14.1M | (aCapacity <= AsAutoString(this)->mInlineCapacity)) { | 160 | 1.71M | newCapacity = AsAutoString(this)->mInlineCapacity; | 161 | 1.71M | newData = (char_type*)AsAutoString(this)->mStorage; | 162 | 1.71M | newDataFlags = DataFlags::TERMINATED | DataFlags::INLINE; | 163 | 12.4M | } else { | 164 | 12.4M | // If |aCapacity > kMaxCapacity|, then our doubling algorithm may not be | 165 | 12.4M | // able to allocate it. Just bail out in cases like that. We don't want | 166 | 12.4M | // to be allocating 2GB+ strings anyway. | 167 | 12.4M | static_assert((sizeof(nsStringBuffer) & 0x1) == 0, | 168 | 12.4M | "bad size for nsStringBuffer"); | 169 | 12.4M | if (MOZ_UNLIKELY(!CheckCapacity(aCapacity))) { | 170 | 0 | return mozilla::Err(NS_ERROR_OUT_OF_MEMORY); | 171 | 0 | } | 172 | 12.4M | | 173 | 12.4M | // We increase our capacity so that the allocated buffer grows | 174 | 12.4M | // exponentially, which gives us amortized O(1) appending. Below the | 175 | 12.4M | // threshold, we use powers-of-two. Above the threshold, we grow by at | 176 | 12.4M | // least 1.125, rounding up to the nearest MiB. | 177 | 12.4M | const size_type slowGrowthThreshold = 8 * 1024 * 1024; | 178 | 12.4M | | 179 | 12.4M | // nsStringBuffer allocates sizeof(nsStringBuffer) + passed size, and | 180 | 12.4M | // storageSize below wants extra 1 * sizeof(char_type). | 181 | 12.4M | const size_type neededExtraSpace = | 182 | 12.4M | sizeof(nsStringBuffer) / sizeof(char_type) + 1; | 183 | 12.4M | | 184 | 12.4M | size_type temp; | 185 | 12.4M | if (aCapacity >= slowGrowthThreshold) { | 186 | 0 | size_type minNewCapacity = curCapacity + (curCapacity >> 3); // multiply by 1.125 | 187 | 0 | temp = XPCOM_MAX(aCapacity, minNewCapacity) + neededExtraSpace; | 188 | 0 |
| 189 | 0 | // Round up to the next multiple of MiB, but ensure the expected | 190 | 0 | // capacity doesn't include the extra space required by nsStringBuffer | 191 | 0 | // and null-termination. | 192 | 0 | const size_t MiB = 1 << 20; | 193 | 0 | temp = (MiB * ((temp + MiB - 1) / MiB)) - neededExtraSpace; | 194 | 12.4M | } else { | 195 | 12.4M | // Round up to the next power of two. | 196 | 12.4M | temp = | 197 | 12.4M | mozilla::RoundUpPow2(aCapacity + neededExtraSpace) - neededExtraSpace; | 198 | 12.4M | } | 199 | 12.4M | | 200 | 12.4M | newCapacity = XPCOM_MIN(temp, kMaxCapacity); | 201 | 12.4M | MOZ_ASSERT(newCapacity >= aCapacity, | 202 | 12.4M | "should have hit the early return at the top"); | 203 | 12.4M | // Avoid shrinking if the new buffer size is close to the old. Note that | 204 | 12.4M | // unsigned underflow is defined behavior. | 205 | 12.4M | if ((curCapacity - newCapacity) <= kNsStringBufferShrinkingThreshold && | 206 | 12.4M | (this->mDataFlags & DataFlags::REFCOUNTED)) { | 207 | 2.30k | MOZ_ASSERT(aAllowShrinking, "How come we didn't return earlier?"); | 208 | 2.30k | // We're already close enough to the right size. | 209 | 2.30k | newData = oldData; | 210 | 2.30k | newCapacity = curCapacity; | 211 | 12.4M | } else { | 212 | 12.4M | size_type storageSize = (newCapacity + 1) * sizeof(char_type); | 213 | 12.4M | // Since we allocate only by powers of 2 we always fit into a full mozjemalloc | 214 | 12.4M | // bucket, it's not useful to use realloc, which may spend time uselessly | 215 | 12.4M | // copying too much. | 216 | 12.4M | nsStringBuffer* newHdr = nsStringBuffer::Alloc(storageSize).take(); | 217 | 12.4M | if (newHdr) { | 218 | 12.4M | newData = (char_type*)newHdr->Data(); | 219 | 12.4M | } else if (shrinking) { | 220 | 0 | // We're still in a consistent state. | 221 | 0 | // | 222 | 0 | // Since shrinking is just a memory footprint optimization, we | 223 | 0 | // don't propagate OOM if we tried to shrink in order to avoid | 224 | 0 | // OOM crashes from infallible callers. If we're lucky, soon enough | 225 | 0 | // a fallible caller reaches OOM and is able to deal or we end up | 226 | 0 | // disposing of this string before reaching OOM again. | 227 | 0 | newData = oldData; | 228 | 0 | newCapacity = curCapacity; | 229 | 0 | } else { | 230 | 0 | return mozilla::Err(NS_ERROR_OUT_OF_MEMORY); | 231 | 0 | } | 232 | 12.4M | } | 233 | 12.4M | newDataFlags = DataFlags::TERMINATED | DataFlags::REFCOUNTED; | 234 | 12.4M | } | 235 | 14.1M | | 236 | 14.1M | this->mData = newData; | 237 | 14.1M | this->mDataFlags = newDataFlags; | 238 | 14.1M | | 239 | 14.1M | if (oldData == newData) { | 240 | 1.70M | char_traits::move( | 241 | 1.70M | newData + aNewSuffixStart, oldData + aOldSuffixStart, aSuffixLength); | 242 | 1.70M | if (aSuffixLength) { | 243 | 0 | char_traits::uninitialize( | 244 | 0 | this->mData + aPrefixToPreserve, | 245 | 0 | XPCOM_MIN(size_t(aNewSuffixStart - aPrefixToPreserve), | 246 | 0 | kNsStringBufferMaxPoison)); | 247 | 0 | char_traits::uninitialize( | 248 | 0 | this->mData + aNewSuffixStart + aSuffixLength, | 249 | 0 | XPCOM_MIN(size_t(newCapacity + 1 - aNewSuffixStart - aSuffixLength), | 250 | 0 | kNsStringBufferMaxPoison)); | 251 | 1.70M | } else { | 252 | 1.70M | char_traits::uninitialize( | 253 | 1.70M | this->mData + aPrefixToPreserve, | 254 | 1.70M | XPCOM_MIN(size_t(newCapacity + 1 - aPrefixToPreserve), | 255 | 1.70M | kNsStringBufferMaxPoison)); | 256 | 1.70M | } | 257 | 12.4M | } else { | 258 | 12.4M | char_traits::copy(newData, oldData, aPrefixToPreserve); | 259 | 12.4M | char_traits::copy( | 260 | 12.4M | newData + aNewSuffixStart, oldData + aOldSuffixStart, aSuffixLength); | 261 | 12.4M | ::ReleaseData(oldData, oldFlags); | 262 | 12.4M | } | 263 | 14.1M | | 264 | 14.1M | return newCapacity; | 265 | 14.1M | } |
|
266 | | |
267 | | template<typename T> |
268 | | void |
269 | | nsTSubstring<T>::FinishBulkWriteImpl(size_type aLength) |
270 | 91.8M | { |
271 | 91.8M | MOZ_ASSERT(aLength != UINT32_MAX, "OOM magic value passed as length."); |
272 | 91.8M | if (aLength) { |
273 | 91.8M | FinishBulkWriteImplImpl(aLength); |
274 | 91.8M | } else { |
275 | 22.1k | ::ReleaseData(this->mData, this->mDataFlags); |
276 | 22.1k | SetToEmptyBuffer(); |
277 | 22.1k | } |
278 | 91.8M | AssertValid(); |
279 | 91.8M | } nsTSubstring<char>::FinishBulkWriteImpl(unsigned int) Line | Count | Source | 270 | 43.0M | { | 271 | 43.0M | MOZ_ASSERT(aLength != UINT32_MAX, "OOM magic value passed as length."); | 272 | 43.0M | if (aLength) { | 273 | 43.0M | FinishBulkWriteImplImpl(aLength); | 274 | 43.0M | } else { | 275 | 22.1k | ::ReleaseData(this->mData, this->mDataFlags); | 276 | 22.1k | SetToEmptyBuffer(); | 277 | 22.1k | } | 278 | 43.0M | AssertValid(); | 279 | 43.0M | } |
nsTSubstring<char16_t>::FinishBulkWriteImpl(unsigned int) Line | Count | Source | 270 | 48.7M | { | 271 | 48.7M | MOZ_ASSERT(aLength != UINT32_MAX, "OOM magic value passed as length."); | 272 | 48.7M | if (aLength) { | 273 | 48.7M | FinishBulkWriteImplImpl(aLength); | 274 | 48.7M | } else { | 275 | 50 | ::ReleaseData(this->mData, this->mDataFlags); | 276 | 50 | SetToEmptyBuffer(); | 277 | 50 | } | 278 | 48.7M | AssertValid(); | 279 | 48.7M | } |
|
280 | | |
281 | | template <typename T> |
282 | | void |
283 | | nsTSubstring<T>::Finalize() |
284 | 225M | { |
285 | 225M | ::ReleaseData(this->mData, this->mDataFlags); |
286 | 225M | // this->mData, this->mLength, and this->mDataFlags are purposefully left dangling |
287 | 225M | } nsTSubstring<char>::Finalize() Line | Count | Source | 284 | 207M | { | 285 | 207M | ::ReleaseData(this->mData, this->mDataFlags); | 286 | 207M | // this->mData, this->mLength, and this->mDataFlags are purposefully left dangling | 287 | 207M | } |
nsTSubstring<char16_t>::Finalize() Line | Count | Source | 284 | 17.5M | { | 285 | 17.5M | ::ReleaseData(this->mData, this->mDataFlags); | 286 | 17.5M | // this->mData, this->mLength, and this->mDataFlags are purposefully left dangling | 287 | 17.5M | } |
|
288 | | |
289 | | template <typename T> |
290 | | bool |
291 | | nsTSubstring<T>::ReplacePrep(index_type aCutStart, |
292 | | size_type aCutLength, |
293 | | size_type aNewLength) |
294 | 1.06M | { |
295 | 1.06M | aCutLength = XPCOM_MIN(aCutLength, this->mLength - aCutStart); |
296 | 1.06M | |
297 | 1.06M | mozilla::CheckedInt<size_type> newTotalLen = this->mLength; |
298 | 1.06M | newTotalLen += aNewLength; |
299 | 1.06M | newTotalLen -= aCutLength; |
300 | 1.06M | if (!newTotalLen.isValid()) { |
301 | 0 | return false; |
302 | 0 | } |
303 | 1.06M | |
304 | 1.06M | if (aCutStart == this->mLength && Capacity() > newTotalLen.value()) { |
305 | 2.00k | this->mDataFlags &= ~DataFlags::VOIDED; |
306 | 2.00k | this->mData[newTotalLen.value()] = char_type(0); |
307 | 2.00k | this->mLength = newTotalLen.value(); |
308 | 2.00k | return true; |
309 | 2.00k | } |
310 | 1.06M | |
311 | 1.06M | return ReplacePrepInternal(aCutStart, aCutLength, aNewLength, |
312 | 1.06M | newTotalLen.value()); |
313 | 1.06M | } nsTSubstring<char>::ReplacePrep(unsigned int, unsigned int, unsigned int) Line | Count | Source | 294 | 5.51k | { | 295 | 5.51k | aCutLength = XPCOM_MIN(aCutLength, this->mLength - aCutStart); | 296 | 5.51k | | 297 | 5.51k | mozilla::CheckedInt<size_type> newTotalLen = this->mLength; | 298 | 5.51k | newTotalLen += aNewLength; | 299 | 5.51k | newTotalLen -= aCutLength; | 300 | 5.51k | if (!newTotalLen.isValid()) { | 301 | 0 | return false; | 302 | 0 | } | 303 | 5.51k | | 304 | 5.51k | if (aCutStart == this->mLength && Capacity() > newTotalLen.value()) { | 305 | 2.00k | this->mDataFlags &= ~DataFlags::VOIDED; | 306 | 2.00k | this->mData[newTotalLen.value()] = char_type(0); | 307 | 2.00k | this->mLength = newTotalLen.value(); | 308 | 2.00k | return true; | 309 | 2.00k | } | 310 | 3.51k | | 311 | 3.51k | return ReplacePrepInternal(aCutStart, aCutLength, aNewLength, | 312 | 3.51k | newTotalLen.value()); | 313 | 3.51k | } |
nsTSubstring<char16_t>::ReplacePrep(unsigned int, unsigned int, unsigned int) Line | Count | Source | 294 | 1.06M | { | 295 | 1.06M | aCutLength = XPCOM_MIN(aCutLength, this->mLength - aCutStart); | 296 | 1.06M | | 297 | 1.06M | mozilla::CheckedInt<size_type> newTotalLen = this->mLength; | 298 | 1.06M | newTotalLen += aNewLength; | 299 | 1.06M | newTotalLen -= aCutLength; | 300 | 1.06M | if (!newTotalLen.isValid()) { | 301 | 0 | return false; | 302 | 0 | } | 303 | 1.06M | | 304 | 1.06M | if (aCutStart == this->mLength && Capacity() > newTotalLen.value()) { | 305 | 0 | this->mDataFlags &= ~DataFlags::VOIDED; | 306 | 0 | this->mData[newTotalLen.value()] = char_type(0); | 307 | 0 | this->mLength = newTotalLen.value(); | 308 | 0 | return true; | 309 | 0 | } | 310 | 1.06M | | 311 | 1.06M | return ReplacePrepInternal(aCutStart, aCutLength, aNewLength, | 312 | 1.06M | newTotalLen.value()); | 313 | 1.06M | } |
|
314 | | |
315 | | template <typename T> |
316 | | bool |
317 | | nsTSubstring<T>::ReplacePrepInternal(index_type aCutStart, size_type aCutLen, |
318 | | size_type aFragLen, size_type aNewLen) |
319 | 1.06M | { |
320 | 1.06M | size_type newSuffixStart = aCutStart + aFragLen; |
321 | 1.06M | size_type oldSuffixStart = aCutStart + aCutLen; |
322 | 1.06M | size_type suffixLength = this->mLength - oldSuffixStart; |
323 | 1.06M | |
324 | 1.06M | mozilla::Result<uint32_t, nsresult> r = StartBulkWriteImpl( |
325 | 1.06M | aNewLen, aCutStart, false, suffixLength, oldSuffixStart, newSuffixStart); |
326 | 1.06M | if (r.isErr()) { |
327 | 0 | return false; |
328 | 0 | } |
329 | 1.06M | FinishBulkWriteImpl(aNewLen); |
330 | 1.06M | return true; |
331 | 1.06M | } nsTSubstring<char>::ReplacePrepInternal(unsigned int, unsigned int, unsigned int, unsigned int) Line | Count | Source | 319 | 3.51k | { | 320 | 3.51k | size_type newSuffixStart = aCutStart + aFragLen; | 321 | 3.51k | size_type oldSuffixStart = aCutStart + aCutLen; | 322 | 3.51k | size_type suffixLength = this->mLength - oldSuffixStart; | 323 | 3.51k | | 324 | 3.51k | mozilla::Result<uint32_t, nsresult> r = StartBulkWriteImpl( | 325 | 3.51k | aNewLen, aCutStart, false, suffixLength, oldSuffixStart, newSuffixStart); | 326 | 3.51k | if (r.isErr()) { | 327 | 0 | return false; | 328 | 0 | } | 329 | 3.51k | FinishBulkWriteImpl(aNewLen); | 330 | 3.51k | return true; | 331 | 3.51k | } |
nsTSubstring<char16_t>::ReplacePrepInternal(unsigned int, unsigned int, unsigned int, unsigned int) Line | Count | Source | 319 | 1.06M | { | 320 | 1.06M | size_type newSuffixStart = aCutStart + aFragLen; | 321 | 1.06M | size_type oldSuffixStart = aCutStart + aCutLen; | 322 | 1.06M | size_type suffixLength = this->mLength - oldSuffixStart; | 323 | 1.06M | | 324 | 1.06M | mozilla::Result<uint32_t, nsresult> r = StartBulkWriteImpl( | 325 | 1.06M | aNewLen, aCutStart, false, suffixLength, oldSuffixStart, newSuffixStart); | 326 | 1.06M | if (r.isErr()) { | 327 | 0 | return false; | 328 | 0 | } | 329 | 1.06M | FinishBulkWriteImpl(aNewLen); | 330 | 1.06M | return true; | 331 | 1.06M | } |
|
332 | | |
333 | | template <typename T> |
334 | | typename nsTSubstring<T>::size_type |
335 | | nsTSubstring<T>::Capacity() const |
336 | 95.0M | { |
337 | 95.0M | // return 0 to indicate an immutable or 0-sized buffer |
338 | 95.0M | |
339 | 95.0M | size_type capacity; |
340 | 95.0M | if (this->mDataFlags & DataFlags::REFCOUNTED) { |
341 | 42.4M | // if the string is readonly, then we pretend that it has no capacity. |
342 | 42.4M | nsStringBuffer* hdr = nsStringBuffer::FromData(this->mData); |
343 | 42.4M | if (hdr->IsReadonly()) { |
344 | 3.61M | capacity = 0; |
345 | 38.8M | } else { |
346 | 38.8M | capacity = (hdr->StorageSize() / sizeof(char_type)) - 1; |
347 | 38.8M | } |
348 | 52.6M | } else if (this->mDataFlags & DataFlags::INLINE) { |
349 | 31.3M | capacity = AsAutoString(this)->mInlineCapacity; |
350 | 31.3M | } else if (this->mDataFlags & DataFlags::OWNED) { |
351 | 0 | // we don't store the capacity of an adopted buffer because that would |
352 | 0 | // require an additional member field. the best we can do is base the |
353 | 0 | // capacity on our length. remains to be seen if this is the right |
354 | 0 | // trade-off. |
355 | 0 | capacity = this->mLength; |
356 | 21.3M | } else { |
357 | 21.3M | capacity = 0; |
358 | 21.3M | } |
359 | 95.0M | |
360 | 95.0M | return capacity; |
361 | 95.0M | } nsTSubstring<char>::Capacity() const Line | Count | Source | 336 | 46.1M | { | 337 | 46.1M | // return 0 to indicate an immutable or 0-sized buffer | 338 | 46.1M | | 339 | 46.1M | size_type capacity; | 340 | 46.1M | if (this->mDataFlags & DataFlags::REFCOUNTED) { | 341 | 1.31M | // if the string is readonly, then we pretend that it has no capacity. | 342 | 1.31M | nsStringBuffer* hdr = nsStringBuffer::FromData(this->mData); | 343 | 1.31M | if (hdr->IsReadonly()) { | 344 | 9.46k | capacity = 0; | 345 | 1.30M | } else { | 346 | 1.30M | capacity = (hdr->StorageSize() / sizeof(char_type)) - 1; | 347 | 1.30M | } | 348 | 44.8M | } else if (this->mDataFlags & DataFlags::INLINE) { | 349 | 28.4M | capacity = AsAutoString(this)->mInlineCapacity; | 350 | 28.4M | } else if (this->mDataFlags & DataFlags::OWNED) { | 351 | 0 | // we don't store the capacity of an adopted buffer because that would | 352 | 0 | // require an additional member field. the best we can do is base the | 353 | 0 | // capacity on our length. remains to be seen if this is the right | 354 | 0 | // trade-off. | 355 | 0 | capacity = this->mLength; | 356 | 16.4M | } else { | 357 | 16.4M | capacity = 0; | 358 | 16.4M | } | 359 | 46.1M | | 360 | 46.1M | return capacity; | 361 | 46.1M | } |
nsTSubstring<char16_t>::Capacity() const Line | Count | Source | 336 | 48.8M | { | 337 | 48.8M | // return 0 to indicate an immutable or 0-sized buffer | 338 | 48.8M | | 339 | 48.8M | size_type capacity; | 340 | 48.8M | if (this->mDataFlags & DataFlags::REFCOUNTED) { | 341 | 41.0M | // if the string is readonly, then we pretend that it has no capacity. | 342 | 41.0M | nsStringBuffer* hdr = nsStringBuffer::FromData(this->mData); | 343 | 41.0M | if (hdr->IsReadonly()) { | 344 | 3.60M | capacity = 0; | 345 | 37.4M | } else { | 346 | 37.4M | capacity = (hdr->StorageSize() / sizeof(char_type)) - 1; | 347 | 37.4M | } | 348 | 41.0M | } else if (this->mDataFlags & DataFlags::INLINE) { | 349 | 2.86M | capacity = AsAutoString(this)->mInlineCapacity; | 350 | 4.89M | } else if (this->mDataFlags & DataFlags::OWNED) { | 351 | 0 | // we don't store the capacity of an adopted buffer because that would | 352 | 0 | // require an additional member field. the best we can do is base the | 353 | 0 | // capacity on our length. remains to be seen if this is the right | 354 | 0 | // trade-off. | 355 | 0 | capacity = this->mLength; | 356 | 4.89M | } else { | 357 | 4.89M | capacity = 0; | 358 | 4.89M | } | 359 | 48.8M | | 360 | 48.8M | return capacity; | 361 | 48.8M | } |
|
362 | | |
363 | | template <typename T> |
364 | | bool |
365 | | nsTSubstring<T>::EnsureMutable(size_type aNewLen) |
366 | 21.0M | { |
367 | 21.0M | if (aNewLen == size_type(-1) || aNewLen == this->mLength) { |
368 | 21.0M | if (this->mDataFlags & (DataFlags::INLINE | DataFlags::OWNED)) { |
369 | 12.4M | return true; |
370 | 12.4M | } |
371 | 8.63M | if ((this->mDataFlags & DataFlags::REFCOUNTED) && |
372 | 8.63M | !nsStringBuffer::FromData(this->mData)->IsReadonly()) { |
373 | 8.43M | return true; |
374 | 8.43M | } |
375 | 204k | |
376 | 204k | aNewLen = this->mLength; |
377 | 204k | } |
378 | 21.0M | return SetLength(aNewLen, mozilla::fallible); |
379 | 21.0M | } nsTSubstring<char>::EnsureMutable(unsigned int) Line | Count | Source | 366 | 20.6M | { | 367 | 20.6M | if (aNewLen == size_type(-1) || aNewLen == this->mLength) { | 368 | 20.6M | if (this->mDataFlags & (DataFlags::INLINE | DataFlags::OWNED)) { | 369 | 12.4M | return true; | 370 | 12.4M | } | 371 | 8.22M | if ((this->mDataFlags & DataFlags::REFCOUNTED) && | 372 | 8.22M | !nsStringBuffer::FromData(this->mData)->IsReadonly()) { | 373 | 8.21M | return true; | 374 | 8.21M | } | 375 | 14.2k | | 376 | 14.2k | aNewLen = this->mLength; | 377 | 14.2k | } | 378 | 20.6M | return SetLength(aNewLen, mozilla::fallible); | 379 | 20.6M | } |
nsTSubstring<char16_t>::EnsureMutable(unsigned int) Line | Count | Source | 366 | 410k | { | 367 | 410k | if (aNewLen == size_type(-1) || aNewLen == this->mLength) { | 368 | 410k | if (this->mDataFlags & (DataFlags::INLINE | DataFlags::OWNED)) { | 369 | 36 | return true; | 370 | 36 | } | 371 | 410k | if ((this->mDataFlags & DataFlags::REFCOUNTED) && | 372 | 410k | !nsStringBuffer::FromData(this->mData)->IsReadonly()) { | 373 | 219k | return true; | 374 | 219k | } | 375 | 190k | | 376 | 190k | aNewLen = this->mLength; | 377 | 190k | } | 378 | 410k | return SetLength(aNewLen, mozilla::fallible); | 379 | 410k | } |
|
380 | | |
381 | | // --------------------------------------------------------------------------- |
382 | | |
383 | | // This version of Assign is optimized for single-character assignment. |
384 | | template <typename T> |
385 | | void |
386 | | nsTSubstring<T>::Assign(char_type aChar) |
387 | 0 | { |
388 | 0 | if (MOZ_UNLIKELY(!Assign(aChar, mozilla::fallible))) { |
389 | 0 | AllocFailed(1); |
390 | 0 | } |
391 | 0 | } Unexecuted instantiation: nsTSubstring<char>::Assign(char) Unexecuted instantiation: nsTSubstring<char16_t>::Assign(char16_t) |
392 | | |
393 | | template <typename T> |
394 | | bool |
395 | | nsTSubstring<T>::Assign(char_type aChar, const fallible_t&) |
396 | 0 | { |
397 | 0 | auto r = StartBulkWriteImpl(1, 0, true); |
398 | 0 | if (MOZ_UNLIKELY(r.isErr())) { |
399 | 0 | return false; |
400 | 0 | } |
401 | 0 | *this->mData = aChar; |
402 | 0 | FinishBulkWriteImpl(1); |
403 | 0 | return true; |
404 | 0 | } Unexecuted instantiation: nsTSubstring<char>::Assign(char, std::nothrow_t const&) Unexecuted instantiation: nsTSubstring<char16_t>::Assign(char16_t, std::nothrow_t const&) |
405 | | |
406 | | template <typename T> |
407 | | void |
408 | | nsTSubstring<T>::Assign(const char_type* aData, size_type aLength) |
409 | 6.83M | { |
410 | 6.83M | if (MOZ_UNLIKELY(!Assign(aData, aLength, mozilla::fallible))) { |
411 | 0 | AllocFailed(aLength == size_type(-1) ? char_traits::length(aData) |
412 | 0 | : aLength); |
413 | 0 | } |
414 | 6.83M | } nsTSubstring<char>::Assign(char const*, unsigned int) Line | Count | Source | 409 | 6.74M | { | 410 | 6.74M | if (MOZ_UNLIKELY(!Assign(aData, aLength, mozilla::fallible))) { | 411 | 0 | AllocFailed(aLength == size_type(-1) ? char_traits::length(aData) | 412 | 0 | : aLength); | 413 | 0 | } | 414 | 6.74M | } |
nsTSubstring<char16_t>::Assign(char16_t const*, unsigned int) Line | Count | Source | 409 | 94.8k | { | 410 | 94.8k | if (MOZ_UNLIKELY(!Assign(aData, aLength, mozilla::fallible))) { | 411 | 0 | AllocFailed(aLength == size_type(-1) ? char_traits::length(aData) | 412 | 0 | : aLength); | 413 | 0 | } | 414 | 94.8k | } |
|
415 | | |
416 | | template <typename T> |
417 | | bool |
418 | | nsTSubstring<T>::Assign(const char_type* aData, |
419 | | const fallible_t& aFallible) |
420 | 0 | { |
421 | 0 | return Assign(aData, size_type(-1), aFallible); |
422 | 0 | } Unexecuted instantiation: nsTSubstring<char>::Assign(char const*, std::nothrow_t const&) Unexecuted instantiation: nsTSubstring<char16_t>::Assign(char16_t const*, std::nothrow_t const&) |
423 | | |
424 | | template <typename T> |
425 | | bool |
426 | | nsTSubstring<T>::Assign(const char_type* aData, size_type aLength, |
427 | | const fallible_t& aFallible) |
428 | 32.8M | { |
429 | 32.8M | if (!aData || aLength == 0) { |
430 | 2.26M | Truncate(); |
431 | 2.26M | return true; |
432 | 2.26M | } |
433 | 30.5M | |
434 | 30.5M | if (MOZ_UNLIKELY(aLength == size_type(-1))) { |
435 | 4.17M | aLength = char_traits::length(aData); |
436 | 4.17M | } |
437 | 30.5M | |
438 | 30.5M | if (MOZ_UNLIKELY(this->IsDependentOn(aData, aData + aLength))) { |
439 | 0 | return Assign(string_type(aData, aLength), aFallible); |
440 | 0 | } |
441 | 30.5M | |
442 | 30.5M | auto r = StartBulkWriteImpl(aLength, 0, true); |
443 | 30.5M | if (MOZ_UNLIKELY(r.isErr())) { |
444 | 0 | return false; |
445 | 0 | } |
446 | 30.5M | char_traits::copy(this->mData, aData, aLength); |
447 | 30.5M | FinishBulkWriteImpl(aLength); |
448 | 30.5M | return true; |
449 | 30.5M | } nsTSubstring<char>::Assign(char const*, unsigned int, std::nothrow_t const&) Line | Count | Source | 428 | 32.5M | { | 429 | 32.5M | if (!aData || aLength == 0) { | 430 | 2.25M | Truncate(); | 431 | 2.25M | return true; | 432 | 2.25M | } | 433 | 30.2M | | 434 | 30.2M | if (MOZ_UNLIKELY(aLength == size_type(-1))) { | 435 | 4.16M | aLength = char_traits::length(aData); | 436 | 4.16M | } | 437 | 30.2M | | 438 | 30.2M | if (MOZ_UNLIKELY(this->IsDependentOn(aData, aData + aLength))) { | 439 | 0 | return Assign(string_type(aData, aLength), aFallible); | 440 | 0 | } | 441 | 30.2M | | 442 | 30.2M | auto r = StartBulkWriteImpl(aLength, 0, true); | 443 | 30.2M | if (MOZ_UNLIKELY(r.isErr())) { | 444 | 0 | return false; | 445 | 0 | } | 446 | 30.2M | char_traits::copy(this->mData, aData, aLength); | 447 | 30.2M | FinishBulkWriteImpl(aLength); | 448 | 30.2M | return true; | 449 | 30.2M | } |
nsTSubstring<char16_t>::Assign(char16_t const*, unsigned int, std::nothrow_t const&) Line | Count | Source | 428 | 260k | { | 429 | 260k | if (!aData || aLength == 0) { | 430 | 2.65k | Truncate(); | 431 | 2.65k | return true; | 432 | 2.65k | } | 433 | 258k | | 434 | 258k | if (MOZ_UNLIKELY(aLength == size_type(-1))) { | 435 | 8.90k | aLength = char_traits::length(aData); | 436 | 8.90k | } | 437 | 258k | | 438 | 258k | if (MOZ_UNLIKELY(this->IsDependentOn(aData, aData + aLength))) { | 439 | 0 | return Assign(string_type(aData, aLength), aFallible); | 440 | 0 | } | 441 | 258k | | 442 | 258k | auto r = StartBulkWriteImpl(aLength, 0, true); | 443 | 258k | if (MOZ_UNLIKELY(r.isErr())) { | 444 | 0 | return false; | 445 | 0 | } | 446 | 258k | char_traits::copy(this->mData, aData, aLength); | 447 | 258k | FinishBulkWriteImpl(aLength); | 448 | 258k | return true; | 449 | 258k | } |
|
450 | | |
451 | | template <typename T> |
452 | | void |
453 | | nsTSubstring<T>::AssignASCII(const char* aData, size_type aLength) |
454 | 1.60M | { |
455 | 1.60M | if (MOZ_UNLIKELY(!AssignASCII(aData, aLength, mozilla::fallible))) { |
456 | 0 | AllocFailed(aLength); |
457 | 0 | } |
458 | 1.60M | } Unexecuted instantiation: nsTSubstring<char>::AssignASCII(char const*, unsigned int) nsTSubstring<char16_t>::AssignASCII(char const*, unsigned int) Line | Count | Source | 454 | 1.60M | { | 455 | 1.60M | if (MOZ_UNLIKELY(!AssignASCII(aData, aLength, mozilla::fallible))) { | 456 | 0 | AllocFailed(aLength); | 457 | 0 | } | 458 | 1.60M | } |
|
459 | | |
460 | | template <typename T> |
461 | | bool |
462 | | nsTSubstring<T>::AssignASCII(const char* aData, size_type aLength, |
463 | | const fallible_t& aFallible) |
464 | 1.60M | { |
465 | 1.60M | MOZ_ASSERT(aLength != size_type(-1)); |
466 | 1.60M | |
467 | 1.60M | // A Unicode string can't depend on an ASCII string buffer, |
468 | 1.60M | // so this dependence check only applies to CStrings. |
469 | | #ifdef CharT_is_char |
470 | | if (this->IsDependentOn(aData, aData + aLength)) { |
471 | | return Assign(string_type(aData, aLength), aFallible); |
472 | | } |
473 | | #endif |
474 | | |
475 | 1.60M | auto r = StartBulkWriteImpl(aLength, 0, true); |
476 | 1.60M | if (MOZ_UNLIKELY(r.isErr())) { |
477 | 0 | return false; |
478 | 0 | } |
479 | 1.60M | char_traits::copyASCII(this->mData, aData, aLength); |
480 | 1.60M | FinishBulkWriteImpl(aLength); |
481 | 1.60M | return true; |
482 | 1.60M | } Unexecuted instantiation: nsTSubstring<char>::AssignASCII(char const*, unsigned int, std::nothrow_t const&) nsTSubstring<char16_t>::AssignASCII(char const*, unsigned int, std::nothrow_t const&) Line | Count | Source | 464 | 1.60M | { | 465 | 1.60M | MOZ_ASSERT(aLength != size_type(-1)); | 466 | 1.60M | | 467 | 1.60M | // A Unicode string can't depend on an ASCII string buffer, | 468 | 1.60M | // so this dependence check only applies to CStrings. | 469 | | #ifdef CharT_is_char | 470 | | if (this->IsDependentOn(aData, aData + aLength)) { | 471 | | return Assign(string_type(aData, aLength), aFallible); | 472 | | } | 473 | | #endif | 474 | | | 475 | 1.60M | auto r = StartBulkWriteImpl(aLength, 0, true); | 476 | 1.60M | if (MOZ_UNLIKELY(r.isErr())) { | 477 | 0 | return false; | 478 | 0 | } | 479 | 1.60M | char_traits::copyASCII(this->mData, aData, aLength); | 480 | 1.60M | FinishBulkWriteImpl(aLength); | 481 | 1.60M | return true; | 482 | 1.60M | } |
|
483 | | |
484 | | template <typename T> |
485 | | void |
486 | | nsTSubstring<T>::AssignLiteral(const char_type* aData, size_type aLength) |
487 | 18.5k | { |
488 | 18.5k | ::ReleaseData(this->mData, this->mDataFlags); |
489 | 18.5k | SetData(const_cast<char_type*>(aData), aLength, |
490 | 18.5k | DataFlags::TERMINATED | DataFlags::LITERAL); |
491 | 18.5k | } nsTSubstring<char>::AssignLiteral(char const*, unsigned int) Line | Count | Source | 487 | 13.7k | { | 488 | 13.7k | ::ReleaseData(this->mData, this->mDataFlags); | 489 | 13.7k | SetData(const_cast<char_type*>(aData), aLength, | 490 | 13.7k | DataFlags::TERMINATED | DataFlags::LITERAL); | 491 | 13.7k | } |
nsTSubstring<char16_t>::AssignLiteral(char16_t const*, unsigned int) Line | Count | Source | 487 | 4.74k | { | 488 | 4.74k | ::ReleaseData(this->mData, this->mDataFlags); | 489 | 4.74k | SetData(const_cast<char_type*>(aData), aLength, | 490 | 4.74k | DataFlags::TERMINATED | DataFlags::LITERAL); | 491 | 4.74k | } |
|
492 | | |
493 | | template <typename T> |
494 | | void |
495 | | nsTSubstring<T>::Assign(const self_type& aStr) |
496 | 53.7M | { |
497 | 53.7M | if (!Assign(aStr, mozilla::fallible)) { |
498 | 0 | AllocFailed(aStr.Length()); |
499 | 0 | } |
500 | 53.7M | } nsTSubstring<char>::Assign(nsTSubstring<char> const&) Line | Count | Source | 496 | 34.7M | { | 497 | 34.7M | if (!Assign(aStr, mozilla::fallible)) { | 498 | 0 | AllocFailed(aStr.Length()); | 499 | 0 | } | 500 | 34.7M | } |
nsTSubstring<char16_t>::Assign(nsTSubstring<char16_t> const&) Line | Count | Source | 496 | 18.9M | { | 497 | 18.9M | if (!Assign(aStr, mozilla::fallible)) { | 498 | 0 | AllocFailed(aStr.Length()); | 499 | 0 | } | 500 | 18.9M | } |
|
501 | | |
502 | | template <typename T> |
503 | | bool |
504 | | nsTSubstring<T>::Assign(const self_type& aStr, const fallible_t& aFallible) |
505 | 63.3M | { |
506 | 63.3M | // |aStr| could be sharable. We need to check its flags to know how to |
507 | 63.3M | // deal with it. |
508 | 63.3M | |
509 | 63.3M | if (&aStr == this) { |
510 | 0 | return true; |
511 | 0 | } |
512 | 63.3M | |
513 | 63.3M | if (!aStr.mLength) { |
514 | 17.3M | Truncate(); |
515 | 17.3M | this->mDataFlags |= aStr.mDataFlags & DataFlags::VOIDED; |
516 | 17.3M | return true; |
517 | 17.3M | } |
518 | 45.9M | |
519 | 45.9M | if (aStr.mDataFlags & DataFlags::REFCOUNTED) { |
520 | 19.9M | // nice! we can avoid a string copy :-) |
521 | 19.9M | |
522 | 19.9M | // |aStr| should be null-terminated |
523 | 19.9M | NS_ASSERTION(aStr.mDataFlags & DataFlags::TERMINATED, "shared, but not terminated"); |
524 | 19.9M | |
525 | 19.9M | ::ReleaseData(this->mData, this->mDataFlags); |
526 | 19.9M | |
527 | 19.9M | SetData(aStr.mData, aStr.mLength, |
528 | 19.9M | DataFlags::TERMINATED | DataFlags::REFCOUNTED); |
529 | 19.9M | |
530 | 19.9M | // get an owning reference to the this->mData |
531 | 19.9M | nsStringBuffer::FromData(this->mData)->AddRef(); |
532 | 19.9M | return true; |
533 | 25.9M | } else if (aStr.mDataFlags & DataFlags::LITERAL) { |
534 | 10.4k | MOZ_ASSERT(aStr.mDataFlags & DataFlags::TERMINATED, "Unterminated literal"); |
535 | 10.4k | |
536 | 10.4k | AssignLiteral(aStr.mData, aStr.mLength); |
537 | 10.4k | return true; |
538 | 10.4k | } |
539 | 25.9M | |
540 | 25.9M | // else, treat this like an ordinary assignment. |
541 | 25.9M | return Assign(aStr.Data(), aStr.Length(), aFallible); |
542 | 25.9M | } nsTSubstring<char>::Assign(nsTSubstring<char> const&, std::nothrow_t const&) Line | Count | Source | 505 | 44.3M | { | 506 | 44.3M | // |aStr| could be sharable. We need to check its flags to know how to | 507 | 44.3M | // deal with it. | 508 | 44.3M | | 509 | 44.3M | if (&aStr == this) { | 510 | 0 | return true; | 511 | 0 | } | 512 | 44.3M | | 513 | 44.3M | if (!aStr.mLength) { | 514 | 17.3M | Truncate(); | 515 | 17.3M | this->mDataFlags |= aStr.mDataFlags & DataFlags::VOIDED; | 516 | 17.3M | return true; | 517 | 17.3M | } | 518 | 26.9M | | 519 | 26.9M | if (aStr.mDataFlags & DataFlags::REFCOUNTED) { | 520 | 1.17M | // nice! we can avoid a string copy :-) | 521 | 1.17M | | 522 | 1.17M | // |aStr| should be null-terminated | 523 | 1.17M | NS_ASSERTION(aStr.mDataFlags & DataFlags::TERMINATED, "shared, but not terminated"); | 524 | 1.17M | | 525 | 1.17M | ::ReleaseData(this->mData, this->mDataFlags); | 526 | 1.17M | | 527 | 1.17M | SetData(aStr.mData, aStr.mLength, | 528 | 1.17M | DataFlags::TERMINATED | DataFlags::REFCOUNTED); | 529 | 1.17M | | 530 | 1.17M | // get an owning reference to the this->mData | 531 | 1.17M | nsStringBuffer::FromData(this->mData)->AddRef(); | 532 | 1.17M | return true; | 533 | 25.8M | } else if (aStr.mDataFlags & DataFlags::LITERAL) { | 534 | 6.08k | MOZ_ASSERT(aStr.mDataFlags & DataFlags::TERMINATED, "Unterminated literal"); | 535 | 6.08k | | 536 | 6.08k | AssignLiteral(aStr.mData, aStr.mLength); | 537 | 6.08k | return true; | 538 | 6.08k | } | 539 | 25.8M | | 540 | 25.8M | // else, treat this like an ordinary assignment. | 541 | 25.8M | return Assign(aStr.Data(), aStr.Length(), aFallible); | 542 | 25.8M | } |
nsTSubstring<char16_t>::Assign(nsTSubstring<char16_t> const&, std::nothrow_t const&) Line | Count | Source | 505 | 18.9M | { | 506 | 18.9M | // |aStr| could be sharable. We need to check its flags to know how to | 507 | 18.9M | // deal with it. | 508 | 18.9M | | 509 | 18.9M | if (&aStr == this) { | 510 | 0 | return true; | 511 | 0 | } | 512 | 18.9M | | 513 | 18.9M | if (!aStr.mLength) { | 514 | 9.09k | Truncate(); | 515 | 9.09k | this->mDataFlags |= aStr.mDataFlags & DataFlags::VOIDED; | 516 | 9.09k | return true; | 517 | 9.09k | } | 518 | 18.9M | | 519 | 18.9M | if (aStr.mDataFlags & DataFlags::REFCOUNTED) { | 520 | 18.8M | // nice! we can avoid a string copy :-) | 521 | 18.8M | | 522 | 18.8M | // |aStr| should be null-terminated | 523 | 18.8M | NS_ASSERTION(aStr.mDataFlags & DataFlags::TERMINATED, "shared, but not terminated"); | 524 | 18.8M | | 525 | 18.8M | ::ReleaseData(this->mData, this->mDataFlags); | 526 | 18.8M | | 527 | 18.8M | SetData(aStr.mData, aStr.mLength, | 528 | 18.8M | DataFlags::TERMINATED | DataFlags::REFCOUNTED); | 529 | 18.8M | | 530 | 18.8M | // get an owning reference to the this->mData | 531 | 18.8M | nsStringBuffer::FromData(this->mData)->AddRef(); | 532 | 18.8M | return true; | 533 | 18.8M | } else if (aStr.mDataFlags & DataFlags::LITERAL) { | 534 | 4.33k | MOZ_ASSERT(aStr.mDataFlags & DataFlags::TERMINATED, "Unterminated literal"); | 535 | 4.33k | | 536 | 4.33k | AssignLiteral(aStr.mData, aStr.mLength); | 537 | 4.33k | return true; | 538 | 4.33k | } | 539 | 166k | | 540 | 166k | // else, treat this like an ordinary assignment. | 541 | 166k | return Assign(aStr.Data(), aStr.Length(), aFallible); | 542 | 166k | } |
|
543 | | |
544 | | template <typename T> |
545 | | void |
546 | | nsTSubstring<T>::Assign(self_type&& aStr) |
547 | 5.00M | { |
548 | 5.00M | if (!Assign(std::move(aStr), mozilla::fallible)) { |
549 | 0 | AllocFailed(aStr.Length()); |
550 | 0 | } |
551 | 5.00M | } nsTSubstring<char>::Assign(nsTSubstring<char>&&) Line | Count | Source | 547 | 5.00M | { | 548 | 5.00M | if (!Assign(std::move(aStr), mozilla::fallible)) { | 549 | 0 | AllocFailed(aStr.Length()); | 550 | 0 | } | 551 | 5.00M | } |
nsTSubstring<char16_t>::Assign(nsTSubstring<char16_t>&&) Line | Count | Source | 547 | 24 | { | 548 | 24 | if (!Assign(std::move(aStr), mozilla::fallible)) { | 549 | 0 | AllocFailed(aStr.Length()); | 550 | 0 | } | 551 | 24 | } |
|
552 | | |
553 | | template <typename T> |
554 | | bool |
555 | | nsTSubstring<T>::Assign(self_type&& aStr, const fallible_t& aFallible) |
556 | 5.00M | { |
557 | 5.00M | // We're moving |aStr| in this method, so we need to try to steal the data, |
558 | 5.00M | // and in the fallback perform a copy-assignment followed by a truncation of |
559 | 5.00M | // the original string. |
560 | 5.00M | |
561 | 5.00M | if (&aStr == this) { |
562 | 0 | NS_WARNING("Move assigning a string to itself?"); |
563 | 0 | return true; |
564 | 0 | } |
565 | 5.00M | |
566 | 5.00M | if (aStr.mDataFlags & (DataFlags::REFCOUNTED | DataFlags::OWNED)) { |
567 | 1.12M | // If they have a REFCOUNTED or OWNED buffer, we can avoid a copy - so steal |
568 | 1.12M | // their buffer and reset them to the empty string. |
569 | 1.12M | |
570 | 1.12M | // |aStr| should be null-terminated |
571 | 1.12M | NS_ASSERTION(aStr.mDataFlags & DataFlags::TERMINATED, |
572 | 1.12M | "shared or owned, but not terminated"); |
573 | 1.12M | |
574 | 1.12M | ::ReleaseData(this->mData, this->mDataFlags); |
575 | 1.12M | |
576 | 1.12M | SetData(aStr.mData, aStr.mLength, aStr.mDataFlags); |
577 | 1.12M | aStr.SetToEmptyBuffer(); |
578 | 1.12M | return true; |
579 | 1.12M | } |
580 | 3.88M | |
581 | 3.88M | // Otherwise treat this as a normal assignment, and truncate the moved string. |
582 | 3.88M | // We don't truncate the source string if the allocation failed. |
583 | 3.88M | if (!Assign(aStr, aFallible)) { |
584 | 0 | return false; |
585 | 0 | } |
586 | 3.88M | aStr.Truncate(); |
587 | 3.88M | return true; |
588 | 3.88M | } nsTSubstring<char>::Assign(nsTSubstring<char>&&, std::nothrow_t const&) Line | Count | Source | 556 | 5.00M | { | 557 | 5.00M | // We're moving |aStr| in this method, so we need to try to steal the data, | 558 | 5.00M | // and in the fallback perform a copy-assignment followed by a truncation of | 559 | 5.00M | // the original string. | 560 | 5.00M | | 561 | 5.00M | if (&aStr == this) { | 562 | 0 | NS_WARNING("Move assigning a string to itself?"); | 563 | 0 | return true; | 564 | 0 | } | 565 | 5.00M | | 566 | 5.00M | if (aStr.mDataFlags & (DataFlags::REFCOUNTED | DataFlags::OWNED)) { | 567 | 1.12M | // If they have a REFCOUNTED or OWNED buffer, we can avoid a copy - so steal | 568 | 1.12M | // their buffer and reset them to the empty string. | 569 | 1.12M | | 570 | 1.12M | // |aStr| should be null-terminated | 571 | 1.12M | NS_ASSERTION(aStr.mDataFlags & DataFlags::TERMINATED, | 572 | 1.12M | "shared or owned, but not terminated"); | 573 | 1.12M | | 574 | 1.12M | ::ReleaseData(this->mData, this->mDataFlags); | 575 | 1.12M | | 576 | 1.12M | SetData(aStr.mData, aStr.mLength, aStr.mDataFlags); | 577 | 1.12M | aStr.SetToEmptyBuffer(); | 578 | 1.12M | return true; | 579 | 1.12M | } | 580 | 3.88M | | 581 | 3.88M | // Otherwise treat this as a normal assignment, and truncate the moved string. | 582 | 3.88M | // We don't truncate the source string if the allocation failed. | 583 | 3.88M | if (!Assign(aStr, aFallible)) { | 584 | 0 | return false; | 585 | 0 | } | 586 | 3.88M | aStr.Truncate(); | 587 | 3.88M | return true; | 588 | 3.88M | } |
nsTSubstring<char16_t>::Assign(nsTSubstring<char16_t>&&, std::nothrow_t const&) Line | Count | Source | 556 | 24 | { | 557 | 24 | // We're moving |aStr| in this method, so we need to try to steal the data, | 558 | 24 | // and in the fallback perform a copy-assignment followed by a truncation of | 559 | 24 | // the original string. | 560 | 24 | | 561 | 24 | if (&aStr == this) { | 562 | 0 | NS_WARNING("Move assigning a string to itself?"); | 563 | 0 | return true; | 564 | 0 | } | 565 | 24 | | 566 | 24 | if (aStr.mDataFlags & (DataFlags::REFCOUNTED | DataFlags::OWNED)) { | 567 | 21 | // If they have a REFCOUNTED or OWNED buffer, we can avoid a copy - so steal | 568 | 21 | // their buffer and reset them to the empty string. | 569 | 21 | | 570 | 21 | // |aStr| should be null-terminated | 571 | 21 | NS_ASSERTION(aStr.mDataFlags & DataFlags::TERMINATED, | 572 | 21 | "shared or owned, but not terminated"); | 573 | 21 | | 574 | 21 | ::ReleaseData(this->mData, this->mDataFlags); | 575 | 21 | | 576 | 21 | SetData(aStr.mData, aStr.mLength, aStr.mDataFlags); | 577 | 21 | aStr.SetToEmptyBuffer(); | 578 | 21 | return true; | 579 | 21 | } | 580 | 3 | | 581 | 3 | // Otherwise treat this as a normal assignment, and truncate the moved string. | 582 | 3 | // We don't truncate the source string if the allocation failed. | 583 | 3 | if (!Assign(aStr, aFallible)) { | 584 | 0 | return false; | 585 | 0 | } | 586 | 3 | aStr.Truncate(); | 587 | 3 | return true; | 588 | 3 | } |
|
589 | | |
590 | | template <typename T> |
591 | | void |
592 | | nsTSubstring<T>::Assign(const substring_tuple_type& aTuple) |
593 | 35.6k | { |
594 | 35.6k | if (!Assign(aTuple, mozilla::fallible)) { |
595 | 0 | AllocFailed(aTuple.Length()); |
596 | 0 | } |
597 | 35.6k | } nsTSubstring<char>::Assign(nsTSubstringTuple<char> const&) Line | Count | Source | 593 | 35.5k | { | 594 | 35.5k | if (!Assign(aTuple, mozilla::fallible)) { | 595 | 0 | AllocFailed(aTuple.Length()); | 596 | 0 | } | 597 | 35.5k | } |
nsTSubstring<char16_t>::Assign(nsTSubstringTuple<char16_t> const&) Line | Count | Source | 593 | 15 | { | 594 | 15 | if (!Assign(aTuple, mozilla::fallible)) { | 595 | 0 | AllocFailed(aTuple.Length()); | 596 | 0 | } | 597 | 15 | } |
|
598 | | |
599 | | template <typename T> |
600 | | bool |
601 | | nsTSubstring<T>::Assign(const substring_tuple_type& aTuple, |
602 | | const fallible_t& aFallible) |
603 | 35.6k | { |
604 | 35.6k | if (aTuple.IsDependentOn(this->mData, this->mData + this->mLength)) { |
605 | 0 | // take advantage of sharing here... |
606 | 0 | return Assign(string_type(aTuple), aFallible); |
607 | 0 | } |
608 | 35.6k | |
609 | 35.6k | size_type length = aTuple.Length(); |
610 | 35.6k | |
611 | 35.6k | mozilla::Result<uint32_t, nsresult> r = StartBulkWriteImpl(length); |
612 | 35.6k | if (r.isErr()) { |
613 | 0 | return false; |
614 | 0 | } |
615 | 35.6k | |
616 | 35.6k | aTuple.WriteTo(this->mData, length); |
617 | 35.6k | |
618 | 35.6k | FinishBulkWriteImpl(length); |
619 | 35.6k | return true; |
620 | 35.6k | } nsTSubstring<char>::Assign(nsTSubstringTuple<char> const&, std::nothrow_t const&) Line | Count | Source | 603 | 35.5k | { | 604 | 35.5k | if (aTuple.IsDependentOn(this->mData, this->mData + this->mLength)) { | 605 | 0 | // take advantage of sharing here... | 606 | 0 | return Assign(string_type(aTuple), aFallible); | 607 | 0 | } | 608 | 35.5k | | 609 | 35.5k | size_type length = aTuple.Length(); | 610 | 35.5k | | 611 | 35.5k | mozilla::Result<uint32_t, nsresult> r = StartBulkWriteImpl(length); | 612 | 35.5k | if (r.isErr()) { | 613 | 0 | return false; | 614 | 0 | } | 615 | 35.5k | | 616 | 35.5k | aTuple.WriteTo(this->mData, length); | 617 | 35.5k | | 618 | 35.5k | FinishBulkWriteImpl(length); | 619 | 35.5k | return true; | 620 | 35.5k | } |
nsTSubstring<char16_t>::Assign(nsTSubstringTuple<char16_t> const&, std::nothrow_t const&) Line | Count | Source | 603 | 15 | { | 604 | 15 | if (aTuple.IsDependentOn(this->mData, this->mData + this->mLength)) { | 605 | 0 | // take advantage of sharing here... | 606 | 0 | return Assign(string_type(aTuple), aFallible); | 607 | 0 | } | 608 | 15 | | 609 | 15 | size_type length = aTuple.Length(); | 610 | 15 | | 611 | 15 | mozilla::Result<uint32_t, nsresult> r = StartBulkWriteImpl(length); | 612 | 15 | if (r.isErr()) { | 613 | 0 | return false; | 614 | 0 | } | 615 | 15 | | 616 | 15 | aTuple.WriteTo(this->mData, length); | 617 | 15 | | 618 | 15 | FinishBulkWriteImpl(length); | 619 | 15 | return true; | 620 | 15 | } |
|
621 | | |
622 | | template <typename T> |
623 | | void |
624 | | nsTSubstring<T>::Adopt(char_type* aData, size_type aLength) |
625 | 2.73M | { |
626 | 2.73M | if (aData) { |
627 | 2.73M | ::ReleaseData(this->mData, this->mDataFlags); |
628 | 2.73M | |
629 | 2.73M | if (aLength == size_type(-1)) { |
630 | 2.73M | aLength = char_traits::length(aData); |
631 | 2.73M | } |
632 | 2.73M | |
633 | 2.73M | MOZ_RELEASE_ASSERT(CheckCapacity(aLength), "adopting a too-long string"); |
634 | 2.73M | |
635 | 2.73M | SetData(aData, aLength, DataFlags::TERMINATED | DataFlags::OWNED); |
636 | 2.73M | |
637 | 2.73M | STRING_STAT_INCREMENT(Adopt); |
638 | 2.73M | // Treat this as construction of a "StringAdopt" object for leak |
639 | 2.73M | // tracking purposes. |
640 | 2.73M | MOZ_LOG_CTOR(this->mData, "StringAdopt", 1); |
641 | 2.73M | } else { |
642 | 0 | SetIsVoid(true); |
643 | 0 | } |
644 | 2.73M | } nsTSubstring<char>::Adopt(char*, unsigned int) Line | Count | Source | 625 | 2.73M | { | 626 | 2.73M | if (aData) { | 627 | 2.73M | ::ReleaseData(this->mData, this->mDataFlags); | 628 | 2.73M | | 629 | 2.73M | if (aLength == size_type(-1)) { | 630 | 2.73M | aLength = char_traits::length(aData); | 631 | 2.73M | } | 632 | 2.73M | | 633 | 2.73M | MOZ_RELEASE_ASSERT(CheckCapacity(aLength), "adopting a too-long string"); | 634 | 2.73M | | 635 | 2.73M | SetData(aData, aLength, DataFlags::TERMINATED | DataFlags::OWNED); | 636 | 2.73M | | 637 | 2.73M | STRING_STAT_INCREMENT(Adopt); | 638 | 2.73M | // Treat this as construction of a "StringAdopt" object for leak | 639 | 2.73M | // tracking purposes. | 640 | 2.73M | MOZ_LOG_CTOR(this->mData, "StringAdopt", 1); | 641 | 2.73M | } else { | 642 | 0 | SetIsVoid(true); | 643 | 0 | } | 644 | 2.73M | } |
nsTSubstring<char16_t>::Adopt(char16_t*, unsigned int) Line | Count | Source | 625 | 18 | { | 626 | 18 | if (aData) { | 627 | 18 | ::ReleaseData(this->mData, this->mDataFlags); | 628 | 18 | | 629 | 18 | if (aLength == size_type(-1)) { | 630 | 18 | aLength = char_traits::length(aData); | 631 | 18 | } | 632 | 18 | | 633 | 18 | MOZ_RELEASE_ASSERT(CheckCapacity(aLength), "adopting a too-long string"); | 634 | 18 | | 635 | 18 | SetData(aData, aLength, DataFlags::TERMINATED | DataFlags::OWNED); | 636 | 18 | | 637 | 18 | STRING_STAT_INCREMENT(Adopt); | 638 | 18 | // Treat this as construction of a "StringAdopt" object for leak | 639 | 18 | // tracking purposes. | 640 | 18 | MOZ_LOG_CTOR(this->mData, "StringAdopt", 1); | 641 | 18 | } else { | 642 | 0 | SetIsVoid(true); | 643 | 0 | } | 644 | 18 | } |
|
645 | | |
646 | | |
647 | | // This version of Replace is optimized for single-character replacement. |
648 | | template <typename T> |
649 | | void |
650 | | nsTSubstring<T>::Replace(index_type aCutStart, size_type aCutLength, |
651 | | char_type aChar) |
652 | 18 | { |
653 | 18 | aCutStart = XPCOM_MIN(aCutStart, this->Length()); |
654 | 18 | |
655 | 18 | if (ReplacePrep(aCutStart, aCutLength, 1)) { |
656 | 18 | this->mData[aCutStart] = aChar; |
657 | 18 | } |
658 | 18 | } nsTSubstring<char>::Replace(unsigned int, unsigned int, char) Line | Count | Source | 652 | 6 | { | 653 | 6 | aCutStart = XPCOM_MIN(aCutStart, this->Length()); | 654 | 6 | | 655 | 6 | if (ReplacePrep(aCutStart, aCutLength, 1)) { | 656 | 6 | this->mData[aCutStart] = aChar; | 657 | 6 | } | 658 | 6 | } |
nsTSubstring<char16_t>::Replace(unsigned int, unsigned int, char16_t) Line | Count | Source | 652 | 12 | { | 653 | 12 | aCutStart = XPCOM_MIN(aCutStart, this->Length()); | 654 | 12 | | 655 | 12 | if (ReplacePrep(aCutStart, aCutLength, 1)) { | 656 | 12 | this->mData[aCutStart] = aChar; | 657 | 12 | } | 658 | 12 | } |
|
659 | | |
660 | | template <typename T> |
661 | | bool |
662 | | nsTSubstring<T>::Replace(index_type aCutStart, size_type aCutLength, |
663 | | char_type aChar, |
664 | | const fallible_t&) |
665 | 0 | { |
666 | 0 | aCutStart = XPCOM_MIN(aCutStart, this->Length()); |
667 | 0 |
|
668 | 0 | if (!ReplacePrep(aCutStart, aCutLength, 1)) { |
669 | 0 | return false; |
670 | 0 | } |
671 | 0 | |
672 | 0 | this->mData[aCutStart] = aChar; |
673 | 0 |
|
674 | 0 | return true; |
675 | 0 | } Unexecuted instantiation: nsTSubstring<char>::Replace(unsigned int, unsigned int, char, std::nothrow_t const&) Unexecuted instantiation: nsTSubstring<char16_t>::Replace(unsigned int, unsigned int, char16_t, std::nothrow_t const&) |
676 | | |
677 | | template <typename T> |
678 | | void |
679 | | nsTSubstring<T>::Replace(index_type aCutStart, size_type aCutLength, |
680 | | const char_type* aData, size_type aLength) |
681 | 1.06M | { |
682 | 1.06M | if (!Replace(aCutStart, aCutLength, aData, aLength, |
683 | 1.06M | mozilla::fallible)) { |
684 | 0 | AllocFailed(this->Length() - aCutLength + 1); |
685 | 0 | } |
686 | 1.06M | } nsTSubstring<char>::Replace(unsigned int, unsigned int, char const*, unsigned int) Line | Count | Source | 681 | 2.34k | { | 682 | 2.34k | if (!Replace(aCutStart, aCutLength, aData, aLength, | 683 | 2.34k | mozilla::fallible)) { | 684 | 0 | AllocFailed(this->Length() - aCutLength + 1); | 685 | 0 | } | 686 | 2.34k | } |
nsTSubstring<char16_t>::Replace(unsigned int, unsigned int, char16_t const*, unsigned int) Line | Count | Source | 681 | 1.06M | { | 682 | 1.06M | if (!Replace(aCutStart, aCutLength, aData, aLength, | 683 | 1.06M | mozilla::fallible)) { | 684 | 0 | AllocFailed(this->Length() - aCutLength + 1); | 685 | 0 | } | 686 | 1.06M | } |
|
687 | | |
688 | | template <typename T> |
689 | | bool |
690 | | nsTSubstring<T>::Replace(index_type aCutStart, size_type aCutLength, |
691 | | const char_type* aData, size_type aLength, |
692 | | const fallible_t& aFallible) |
693 | 1.06M | { |
694 | 1.06M | // unfortunately, some callers pass null :-( |
695 | 1.06M | if (!aData) { |
696 | 0 | aLength = 0; |
697 | 1.06M | } else { |
698 | 1.06M | if (aLength == size_type(-1)) { |
699 | 0 | aLength = char_traits::length(aData); |
700 | 0 | } |
701 | 1.06M | |
702 | 1.06M | if (this->IsDependentOn(aData, aData + aLength)) { |
703 | 0 | nsTAutoString<T> temp(aData, aLength); |
704 | 0 | return Replace(aCutStart, aCutLength, temp, aFallible); |
705 | 0 | } |
706 | 1.06M | } |
707 | 1.06M | |
708 | 1.06M | aCutStart = XPCOM_MIN(aCutStart, this->Length()); |
709 | 1.06M | |
710 | 1.06M | bool ok = ReplacePrep(aCutStart, aCutLength, aLength); |
711 | 1.06M | if (!ok) { |
712 | 0 | return false; |
713 | 0 | } |
714 | 1.06M | |
715 | 1.06M | if (aLength > 0) { |
716 | 1.71k | char_traits::copy(this->mData + aCutStart, aData, aLength); |
717 | 1.71k | } |
718 | 1.06M | |
719 | 1.06M | return true; |
720 | 1.06M | } nsTSubstring<char>::Replace(unsigned int, unsigned int, char const*, unsigned int, std::nothrow_t const&) Line | Count | Source | 693 | 2.34k | { | 694 | 2.34k | // unfortunately, some callers pass null :-( | 695 | 2.34k | if (!aData) { | 696 | 0 | aLength = 0; | 697 | 2.34k | } else { | 698 | 2.34k | if (aLength == size_type(-1)) { | 699 | 0 | aLength = char_traits::length(aData); | 700 | 0 | } | 701 | 2.34k | | 702 | 2.34k | if (this->IsDependentOn(aData, aData + aLength)) { | 703 | 0 | nsTAutoString<T> temp(aData, aLength); | 704 | 0 | return Replace(aCutStart, aCutLength, temp, aFallible); | 705 | 0 | } | 706 | 2.34k | } | 707 | 2.34k | | 708 | 2.34k | aCutStart = XPCOM_MIN(aCutStart, this->Length()); | 709 | 2.34k | | 710 | 2.34k | bool ok = ReplacePrep(aCutStart, aCutLength, aLength); | 711 | 2.34k | if (!ok) { | 712 | 0 | return false; | 713 | 0 | } | 714 | 2.34k | | 715 | 2.34k | if (aLength > 0) { | 716 | 1.70k | char_traits::copy(this->mData + aCutStart, aData, aLength); | 717 | 1.70k | } | 718 | 2.34k | | 719 | 2.34k | return true; | 720 | 2.34k | } |
nsTSubstring<char16_t>::Replace(unsigned int, unsigned int, char16_t const*, unsigned int, std::nothrow_t const&) Line | Count | Source | 693 | 1.06M | { | 694 | 1.06M | // unfortunately, some callers pass null :-( | 695 | 1.06M | if (!aData) { | 696 | 0 | aLength = 0; | 697 | 1.06M | } else { | 698 | 1.06M | if (aLength == size_type(-1)) { | 699 | 0 | aLength = char_traits::length(aData); | 700 | 0 | } | 701 | 1.06M | | 702 | 1.06M | if (this->IsDependentOn(aData, aData + aLength)) { | 703 | 0 | nsTAutoString<T> temp(aData, aLength); | 704 | 0 | return Replace(aCutStart, aCutLength, temp, aFallible); | 705 | 0 | } | 706 | 1.06M | } | 707 | 1.06M | | 708 | 1.06M | aCutStart = XPCOM_MIN(aCutStart, this->Length()); | 709 | 1.06M | | 710 | 1.06M | bool ok = ReplacePrep(aCutStart, aCutLength, aLength); | 711 | 1.06M | if (!ok) { | 712 | 0 | return false; | 713 | 0 | } | 714 | 1.06M | | 715 | 1.06M | if (aLength > 0) { | 716 | 12 | char_traits::copy(this->mData + aCutStart, aData, aLength); | 717 | 12 | } | 718 | 1.06M | | 719 | 1.06M | return true; | 720 | 1.06M | } |
|
721 | | |
722 | | template <typename T> |
723 | | void |
724 | | nsTSubstring<T>::ReplaceASCII(index_type aCutStart, size_type aCutLength, |
725 | | const char* aData, size_type aLength) |
726 | 0 | { |
727 | 0 | if (!ReplaceASCII(aCutStart, aCutLength, aData, aLength, mozilla::fallible)) { |
728 | 0 | AllocFailed(this->Length() - aCutLength + 1); |
729 | 0 | } |
730 | 0 | } Unexecuted instantiation: nsTSubstring<char>::ReplaceASCII(unsigned int, unsigned int, char const*, unsigned int) Unexecuted instantiation: nsTSubstring<char16_t>::ReplaceASCII(unsigned int, unsigned int, char const*, unsigned int) |
731 | | |
732 | | template <typename T> |
733 | | bool |
734 | | nsTSubstring<T>::ReplaceASCII(index_type aCutStart, size_type aCutLength, |
735 | | const char* aData, size_type aLength, |
736 | | const fallible_t& aFallible) |
737 | 0 | { |
738 | 0 | if (aLength == size_type(-1)) { |
739 | 0 | aLength = strlen(aData); |
740 | 0 | } |
741 | 0 |
|
742 | 0 | // A Unicode string can't depend on an ASCII string buffer, |
743 | 0 | // so this dependence check only applies to CStrings. |
744 | | #ifdef CharT_is_char |
745 | | if (this->IsDependentOn(aData, aData + aLength)) { |
746 | | nsTAutoString_CharT temp(aData, aLength); |
747 | | return Replace(aCutStart, aCutLength, temp, aFallible); |
748 | | } |
749 | | #endif |
750 | |
|
751 | 0 | aCutStart = XPCOM_MIN(aCutStart, this->Length()); |
752 | 0 |
|
753 | 0 | bool ok = ReplacePrep(aCutStart, aCutLength, aLength); |
754 | 0 | if (!ok) { |
755 | 0 | return false; |
756 | 0 | } |
757 | 0 | |
758 | 0 | if (aLength > 0) { |
759 | 0 | char_traits::copyASCII(this->mData + aCutStart, aData, aLength); |
760 | 0 | } |
761 | 0 |
|
762 | 0 | return true; |
763 | 0 | } Unexecuted instantiation: nsTSubstring<char>::ReplaceASCII(unsigned int, unsigned int, char const*, unsigned int, std::nothrow_t const&) Unexecuted instantiation: nsTSubstring<char16_t>::ReplaceASCII(unsigned int, unsigned int, char const*, unsigned int, std::nothrow_t const&) |
764 | | |
765 | | template <typename T> |
766 | | void |
767 | | nsTSubstring<T>::Replace(index_type aCutStart, size_type aCutLength, |
768 | | const substring_tuple_type& aTuple) |
769 | 0 | { |
770 | 0 | if (aTuple.IsDependentOn(this->mData, this->mData + this->mLength)) { |
771 | 0 | nsTAutoString<T> temp(aTuple); |
772 | 0 | Replace(aCutStart, aCutLength, temp); |
773 | 0 | return; |
774 | 0 | } |
775 | 0 | |
776 | 0 | size_type length = aTuple.Length(); |
777 | 0 |
|
778 | 0 | aCutStart = XPCOM_MIN(aCutStart, this->Length()); |
779 | 0 |
|
780 | 0 | if (ReplacePrep(aCutStart, aCutLength, length) && length > 0) { |
781 | 0 | aTuple.WriteTo(this->mData + aCutStart, length); |
782 | 0 | } |
783 | 0 | } Unexecuted instantiation: nsTSubstring<char>::Replace(unsigned int, unsigned int, nsTSubstringTuple<char> const&) Unexecuted instantiation: nsTSubstring<char16_t>::Replace(unsigned int, unsigned int, nsTSubstringTuple<char16_t> const&) |
784 | | |
785 | | template <typename T> |
786 | | void |
787 | | nsTSubstring<T>::ReplaceLiteral(index_type aCutStart, size_type aCutLength, |
788 | | const char_type* aData, size_type aLength) |
789 | 4.43k | { |
790 | 4.43k | aCutStart = XPCOM_MIN(aCutStart, this->Length()); |
791 | 4.43k | |
792 | 4.43k | if (!aCutStart && aCutLength == this->Length() && |
793 | 4.43k | !(this->mDataFlags & DataFlags::REFCOUNTED)) { |
794 | 1.26k | // Check for REFCOUNTED above to avoid undoing the effect of |
795 | 1.26k | // SetCapacity(). |
796 | 1.26k | AssignLiteral(aData, aLength); |
797 | 3.16k | } else if (ReplacePrep(aCutStart, aCutLength, aLength) && aLength > 0) { |
798 | 3.16k | char_traits::copy(this->mData + aCutStart, aData, aLength); |
799 | 3.16k | } |
800 | 4.43k | } nsTSubstring<char>::ReplaceLiteral(unsigned int, unsigned int, char const*, unsigned int) Line | Count | Source | 789 | 4.43k | { | 790 | 4.43k | aCutStart = XPCOM_MIN(aCutStart, this->Length()); | 791 | 4.43k | | 792 | 4.43k | if (!aCutStart && aCutLength == this->Length() && | 793 | 4.43k | !(this->mDataFlags & DataFlags::REFCOUNTED)) { | 794 | 1.26k | // Check for REFCOUNTED above to avoid undoing the effect of | 795 | 1.26k | // SetCapacity(). | 796 | 1.26k | AssignLiteral(aData, aLength); | 797 | 3.16k | } else if (ReplacePrep(aCutStart, aCutLength, aLength) && aLength > 0) { | 798 | 3.16k | char_traits::copy(this->mData + aCutStart, aData, aLength); | 799 | 3.16k | } | 800 | 4.43k | } |
Unexecuted instantiation: nsTSubstring<char16_t>::ReplaceLiteral(unsigned int, unsigned int, char16_t const*, unsigned int) |
801 | | |
802 | | template <typename T> |
803 | | void |
804 | | nsTSubstring<T>::Append(char_type aChar) |
805 | 45.8M | { |
806 | 45.8M | if (MOZ_UNLIKELY(!Append(aChar, mozilla::fallible))) { |
807 | 0 | AllocFailed(this->mLength + 1); |
808 | 0 | } |
809 | 45.8M | } nsTSubstring<char>::Append(char) Line | Count | Source | 805 | 335k | { | 806 | 335k | if (MOZ_UNLIKELY(!Append(aChar, mozilla::fallible))) { | 807 | 0 | AllocFailed(this->mLength + 1); | 808 | 0 | } | 809 | 335k | } |
nsTSubstring<char16_t>::Append(char16_t) Line | Count | Source | 805 | 45.4M | { | 806 | 45.4M | if (MOZ_UNLIKELY(!Append(aChar, mozilla::fallible))) { | 807 | 0 | AllocFailed(this->mLength + 1); | 808 | 0 | } | 809 | 45.4M | } |
|
810 | | |
811 | | template <typename T> |
812 | | bool |
813 | | nsTSubstring<T>::Append(char_type aChar, |
814 | | const fallible_t& aFallible) |
815 | 45.8M | { |
816 | 45.8M | size_type oldLen = this->mLength; |
817 | 45.8M | size_type newLen = oldLen + 1; // Can't overflow |
818 | 45.8M | auto r = StartBulkWriteImpl(newLen, oldLen, false); |
819 | 45.8M | if (MOZ_UNLIKELY(r.isErr())) { |
820 | 0 | return false; |
821 | 0 | } |
822 | 45.8M | this->mData[oldLen] = aChar; |
823 | 45.8M | FinishBulkWriteImpl(newLen); |
824 | 45.8M | return true; |
825 | 45.8M | } nsTSubstring<char>::Append(char, std::nothrow_t const&) Line | Count | Source | 815 | 335k | { | 816 | 335k | size_type oldLen = this->mLength; | 817 | 335k | size_type newLen = oldLen + 1; // Can't overflow | 818 | 335k | auto r = StartBulkWriteImpl(newLen, oldLen, false); | 819 | 335k | if (MOZ_UNLIKELY(r.isErr())) { | 820 | 0 | return false; | 821 | 0 | } | 822 | 335k | this->mData[oldLen] = aChar; | 823 | 335k | FinishBulkWriteImpl(newLen); | 824 | 335k | return true; | 825 | 335k | } |
nsTSubstring<char16_t>::Append(char16_t, std::nothrow_t const&) Line | Count | Source | 815 | 45.4M | { | 816 | 45.4M | size_type oldLen = this->mLength; | 817 | 45.4M | size_type newLen = oldLen + 1; // Can't overflow | 818 | 45.4M | auto r = StartBulkWriteImpl(newLen, oldLen, false); | 819 | 45.4M | if (MOZ_UNLIKELY(r.isErr())) { | 820 | 0 | return false; | 821 | 0 | } | 822 | 45.4M | this->mData[oldLen] = aChar; | 823 | 45.4M | FinishBulkWriteImpl(newLen); | 824 | 45.4M | return true; | 825 | 45.4M | } |
|
826 | | |
827 | | template <typename T> |
828 | | void |
829 | | nsTSubstring<T>::Append(const char_type* aData, size_type aLength) |
830 | 3.88M | { |
831 | 3.88M | if (MOZ_UNLIKELY(!Append(aData, aLength, mozilla::fallible))) { |
832 | 0 | AllocFailed(this->mLength + (aLength == size_type(-1) |
833 | 0 | ? char_traits::length(aData) |
834 | 0 | : aLength)); |
835 | 0 | } |
836 | 3.88M | } nsTSubstring<char>::Append(char const*, unsigned int) Line | Count | Source | 830 | 3.88M | { | 831 | 3.88M | if (MOZ_UNLIKELY(!Append(aData, aLength, mozilla::fallible))) { | 832 | 0 | AllocFailed(this->mLength + (aLength == size_type(-1) | 833 | 0 | ? char_traits::length(aData) | 834 | 0 | : aLength)); | 835 | 0 | } | 836 | 3.88M | } |
nsTSubstring<char16_t>::Append(char16_t const*, unsigned int) Line | Count | Source | 830 | 321 | { | 831 | 321 | if (MOZ_UNLIKELY(!Append(aData, aLength, mozilla::fallible))) { | 832 | 0 | AllocFailed(this->mLength + (aLength == size_type(-1) | 833 | 0 | ? char_traits::length(aData) | 834 | 0 | : aLength)); | 835 | 0 | } | 836 | 321 | } |
|
837 | | |
838 | | template <typename T> |
839 | | bool |
840 | | nsTSubstring<T>::Append(const char_type* aData, size_type aLength, |
841 | | const fallible_t& aFallible) |
842 | 5.11M | { |
843 | 5.11M | if (MOZ_UNLIKELY(aLength == size_type(-1))) { |
844 | 3.86M | aLength = char_traits::length(aData); |
845 | 3.86M | } |
846 | 5.11M | |
847 | 5.11M | if (MOZ_UNLIKELY(!aLength)) { |
848 | 381k | // Avoid undoing the effect of SetCapacity() if both |
849 | 381k | // mLength and aLength are zero. |
850 | 381k | return true; |
851 | 381k | } |
852 | 4.72M | |
853 | 4.72M | if (MOZ_UNLIKELY(this->IsDependentOn(aData, aData + aLength))) { |
854 | 0 | return Append(string_type(aData, aLength), mozilla::fallible); |
855 | 0 | } |
856 | 4.72M | size_type oldLen = this->mLength; |
857 | 4.72M | mozilla::CheckedInt<size_type> newLen(oldLen); |
858 | 4.72M | newLen += aLength; |
859 | 4.72M | if (MOZ_UNLIKELY(!newLen.isValid())) { |
860 | 0 | return false; |
861 | 0 | } |
862 | 4.72M | auto r = StartBulkWriteImpl(newLen.value(), oldLen, false); |
863 | 4.72M | if (MOZ_UNLIKELY(r.isErr())) { |
864 | 0 | return false; |
865 | 0 | } |
866 | 4.72M | char_traits::copy(this->mData + oldLen, aData, aLength); |
867 | 4.72M | FinishBulkWriteImpl(newLen.value()); |
868 | 4.72M | return true; |
869 | 4.72M | } nsTSubstring<char>::Append(char const*, unsigned int, std::nothrow_t const&) Line | Count | Source | 842 | 5.09M | { | 843 | 5.09M | if (MOZ_UNLIKELY(aLength == size_type(-1))) { | 844 | 3.86M | aLength = char_traits::length(aData); | 845 | 3.86M | } | 846 | 5.09M | | 847 | 5.09M | if (MOZ_UNLIKELY(!aLength)) { | 848 | 378k | // Avoid undoing the effect of SetCapacity() if both | 849 | 378k | // mLength and aLength are zero. | 850 | 378k | return true; | 851 | 378k | } | 852 | 4.71M | | 853 | 4.71M | if (MOZ_UNLIKELY(this->IsDependentOn(aData, aData + aLength))) { | 854 | 0 | return Append(string_type(aData, aLength), mozilla::fallible); | 855 | 0 | } | 856 | 4.71M | size_type oldLen = this->mLength; | 857 | 4.71M | mozilla::CheckedInt<size_type> newLen(oldLen); | 858 | 4.71M | newLen += aLength; | 859 | 4.71M | if (MOZ_UNLIKELY(!newLen.isValid())) { | 860 | 0 | return false; | 861 | 0 | } | 862 | 4.71M | auto r = StartBulkWriteImpl(newLen.value(), oldLen, false); | 863 | 4.71M | if (MOZ_UNLIKELY(r.isErr())) { | 864 | 0 | return false; | 865 | 0 | } | 866 | 4.71M | char_traits::copy(this->mData + oldLen, aData, aLength); | 867 | 4.71M | FinishBulkWriteImpl(newLen.value()); | 868 | 4.71M | return true; | 869 | 4.71M | } |
nsTSubstring<char16_t>::Append(char16_t const*, unsigned int, std::nothrow_t const&) Line | Count | Source | 842 | 18.7k | { | 843 | 18.7k | if (MOZ_UNLIKELY(aLength == size_type(-1))) { | 844 | 285 | aLength = char_traits::length(aData); | 845 | 285 | } | 846 | 18.7k | | 847 | 18.7k | if (MOZ_UNLIKELY(!aLength)) { | 848 | 2.61k | // Avoid undoing the effect of SetCapacity() if both | 849 | 2.61k | // mLength and aLength are zero. | 850 | 2.61k | return true; | 851 | 2.61k | } | 852 | 16.1k | | 853 | 16.1k | if (MOZ_UNLIKELY(this->IsDependentOn(aData, aData + aLength))) { | 854 | 0 | return Append(string_type(aData, aLength), mozilla::fallible); | 855 | 0 | } | 856 | 16.1k | size_type oldLen = this->mLength; | 857 | 16.1k | mozilla::CheckedInt<size_type> newLen(oldLen); | 858 | 16.1k | newLen += aLength; | 859 | 16.1k | if (MOZ_UNLIKELY(!newLen.isValid())) { | 860 | 0 | return false; | 861 | 0 | } | 862 | 16.1k | auto r = StartBulkWriteImpl(newLen.value(), oldLen, false); | 863 | 16.1k | if (MOZ_UNLIKELY(r.isErr())) { | 864 | 0 | return false; | 865 | 0 | } | 866 | 16.1k | char_traits::copy(this->mData + oldLen, aData, aLength); | 867 | 16.1k | FinishBulkWriteImpl(newLen.value()); | 868 | 16.1k | return true; | 869 | 16.1k | } |
|
870 | | |
871 | | template <typename T> |
872 | | void |
873 | | nsTSubstring<T>::AppendASCII(const char* aData, size_type aLength) |
874 | 37.1k | { |
875 | 37.1k | if (MOZ_UNLIKELY(!AppendASCII(aData, aLength, mozilla::fallible))) { |
876 | 0 | AllocFailed(this->mLength + |
877 | 0 | (aLength == size_type(-1) ? strlen(aData) : aLength)); |
878 | 0 | } |
879 | 37.1k | } nsTSubstring<char>::AppendASCII(char const*, unsigned int) Line | Count | Source | 874 | 28.3k | { | 875 | 28.3k | if (MOZ_UNLIKELY(!AppendASCII(aData, aLength, mozilla::fallible))) { | 876 | 0 | AllocFailed(this->mLength + | 877 | 0 | (aLength == size_type(-1) ? strlen(aData) : aLength)); | 878 | 0 | } | 879 | 28.3k | } |
nsTSubstring<char16_t>::AppendASCII(char const*, unsigned int) Line | Count | Source | 874 | 8.72k | { | 875 | 8.72k | if (MOZ_UNLIKELY(!AppendASCII(aData, aLength, mozilla::fallible))) { | 876 | 0 | AllocFailed(this->mLength + | 877 | 0 | (aLength == size_type(-1) ? strlen(aData) : aLength)); | 878 | 0 | } | 879 | 8.72k | } |
|
880 | | |
881 | | template <typename T> |
882 | | bool |
883 | | nsTSubstring<T>::AppendASCII(const char* aData, |
884 | | const fallible_t& aFallible) |
885 | 0 | { |
886 | 0 | return AppendASCII(aData, size_type(-1), aFallible); |
887 | 0 | } Unexecuted instantiation: nsTSubstring<char>::AppendASCII(char const*, std::nothrow_t const&) Unexecuted instantiation: nsTSubstring<char16_t>::AppendASCII(char const*, std::nothrow_t const&) |
888 | | |
889 | | template <typename T> |
890 | | bool |
891 | | nsTSubstring<T>::AppendASCII(const char* aData, size_type aLength, |
892 | | const fallible_t& aFallible) |
893 | 37.1k | { |
894 | 37.1k | if (MOZ_UNLIKELY(aLength == size_type(-1))) { |
895 | 0 | aLength = strlen(aData); |
896 | 0 | } |
897 | 37.1k | |
898 | 37.1k | if (MOZ_UNLIKELY(!aLength)) { |
899 | 0 | // Avoid undoing the effect of SetCapacity() if both |
900 | 0 | // mLength and aLength are zero. |
901 | 0 | return true; |
902 | 0 | } |
903 | 37.1k | |
904 | | #ifdef CharT_is_char |
905 | | // 16-bit string can't depend on an 8-bit buffer |
906 | | if (MOZ_UNLIKELY(this->IsDependentOn(aData, aData + aLength))) { |
907 | | return Append(string_type(aData, aLength), mozilla::fallible); |
908 | | } |
909 | | #endif |
910 | 37.1k | size_type oldLen = this->mLength; |
911 | 37.1k | mozilla::CheckedInt<size_type> newLen(oldLen); |
912 | 37.1k | newLen += aLength; |
913 | 37.1k | if (MOZ_UNLIKELY(!newLen.isValid())) { |
914 | 0 | return false; |
915 | 0 | } |
916 | 37.1k | auto r = StartBulkWriteImpl(newLen.value(), oldLen, false); |
917 | 37.1k | if (MOZ_UNLIKELY(r.isErr())) { |
918 | 0 | return false; |
919 | 0 | } |
920 | 37.1k | char_traits::copyASCII(this->mData + oldLen, aData, aLength); |
921 | 37.1k | FinishBulkWriteImpl(newLen.value()); |
922 | 37.1k | return true; |
923 | 37.1k | } nsTSubstring<char>::AppendASCII(char const*, unsigned int, std::nothrow_t const&) Line | Count | Source | 893 | 28.3k | { | 894 | 28.3k | if (MOZ_UNLIKELY(aLength == size_type(-1))) { | 895 | 0 | aLength = strlen(aData); | 896 | 0 | } | 897 | 28.3k | | 898 | 28.3k | if (MOZ_UNLIKELY(!aLength)) { | 899 | 0 | // Avoid undoing the effect of SetCapacity() if both | 900 | 0 | // mLength and aLength are zero. | 901 | 0 | return true; | 902 | 0 | } | 903 | 28.3k | | 904 | | #ifdef CharT_is_char | 905 | | // 16-bit string can't depend on an 8-bit buffer | 906 | | if (MOZ_UNLIKELY(this->IsDependentOn(aData, aData + aLength))) { | 907 | | return Append(string_type(aData, aLength), mozilla::fallible); | 908 | | } | 909 | | #endif | 910 | 28.3k | size_type oldLen = this->mLength; | 911 | 28.3k | mozilla::CheckedInt<size_type> newLen(oldLen); | 912 | 28.3k | newLen += aLength; | 913 | 28.3k | if (MOZ_UNLIKELY(!newLen.isValid())) { | 914 | 0 | return false; | 915 | 0 | } | 916 | 28.3k | auto r = StartBulkWriteImpl(newLen.value(), oldLen, false); | 917 | 28.3k | if (MOZ_UNLIKELY(r.isErr())) { | 918 | 0 | return false; | 919 | 0 | } | 920 | 28.3k | char_traits::copyASCII(this->mData + oldLen, aData, aLength); | 921 | 28.3k | FinishBulkWriteImpl(newLen.value()); | 922 | 28.3k | return true; | 923 | 28.3k | } |
nsTSubstring<char16_t>::AppendASCII(char const*, unsigned int, std::nothrow_t const&) Line | Count | Source | 893 | 8.72k | { | 894 | 8.72k | if (MOZ_UNLIKELY(aLength == size_type(-1))) { | 895 | 0 | aLength = strlen(aData); | 896 | 0 | } | 897 | 8.72k | | 898 | 8.72k | if (MOZ_UNLIKELY(!aLength)) { | 899 | 0 | // Avoid undoing the effect of SetCapacity() if both | 900 | 0 | // mLength and aLength are zero. | 901 | 0 | return true; | 902 | 0 | } | 903 | 8.72k | | 904 | | #ifdef CharT_is_char | 905 | | // 16-bit string can't depend on an 8-bit buffer | 906 | | if (MOZ_UNLIKELY(this->IsDependentOn(aData, aData + aLength))) { | 907 | | return Append(string_type(aData, aLength), mozilla::fallible); | 908 | | } | 909 | | #endif | 910 | 8.72k | size_type oldLen = this->mLength; | 911 | 8.72k | mozilla::CheckedInt<size_type> newLen(oldLen); | 912 | 8.72k | newLen += aLength; | 913 | 8.72k | if (MOZ_UNLIKELY(!newLen.isValid())) { | 914 | 0 | return false; | 915 | 0 | } | 916 | 8.72k | auto r = StartBulkWriteImpl(newLen.value(), oldLen, false); | 917 | 8.72k | if (MOZ_UNLIKELY(r.isErr())) { | 918 | 0 | return false; | 919 | 0 | } | 920 | 8.72k | char_traits::copyASCII(this->mData + oldLen, aData, aLength); | 921 | 8.72k | FinishBulkWriteImpl(newLen.value()); | 922 | 8.72k | return true; | 923 | 8.72k | } |
|
924 | | |
925 | | template <typename T> |
926 | | void |
927 | | nsTSubstring<T>::Append(const self_type& aStr) |
928 | 137k | { |
929 | 137k | if (MOZ_UNLIKELY(!Append(aStr, mozilla::fallible))) { |
930 | 0 | AllocFailed(this->mLength + aStr.Length()); |
931 | 0 | } |
932 | 137k | } nsTSubstring<char>::Append(nsTSubstring<char> const&) Line | Count | Source | 928 | 78.4k | { | 929 | 78.4k | if (MOZ_UNLIKELY(!Append(aStr, mozilla::fallible))) { | 930 | 0 | AllocFailed(this->mLength + aStr.Length()); | 931 | 0 | } | 932 | 78.4k | } |
nsTSubstring<char16_t>::Append(nsTSubstring<char16_t> const&) Line | Count | Source | 928 | 58.7k | { | 929 | 58.7k | if (MOZ_UNLIKELY(!Append(aStr, mozilla::fallible))) { | 930 | 0 | AllocFailed(this->mLength + aStr.Length()); | 931 | 0 | } | 932 | 58.7k | } |
|
933 | | |
934 | | template <typename T> |
935 | | bool |
936 | | nsTSubstring<T>::Append(const self_type& aStr, const fallible_t& aFallible) |
937 | 137k | { |
938 | 137k | // Check refcounted to avoid undoing the effects of SetCapacity(). |
939 | 137k | if (MOZ_UNLIKELY(!this->mLength && !(this->mDataFlags & DataFlags::REFCOUNTED))) { |
940 | 70.0k | return Assign(aStr, mozilla::fallible); |
941 | 70.0k | } |
942 | 67.2k | return Append(aStr.BeginReading(), aStr.Length(), mozilla::fallible); |
943 | 67.2k | } nsTSubstring<char>::Append(nsTSubstring<char> const&, std::nothrow_t const&) Line | Count | Source | 937 | 78.4k | { | 938 | 78.4k | // Check refcounted to avoid undoing the effects of SetCapacity(). | 939 | 78.4k | if (MOZ_UNLIKELY(!this->mLength && !(this->mDataFlags & DataFlags::REFCOUNTED))) { | 940 | 29.6k | return Assign(aStr, mozilla::fallible); | 941 | 29.6k | } | 942 | 48.8k | return Append(aStr.BeginReading(), aStr.Length(), mozilla::fallible); | 943 | 48.8k | } |
nsTSubstring<char16_t>::Append(nsTSubstring<char16_t> const&, std::nothrow_t const&) Line | Count | Source | 937 | 58.7k | { | 938 | 58.7k | // Check refcounted to avoid undoing the effects of SetCapacity(). | 939 | 58.7k | if (MOZ_UNLIKELY(!this->mLength && !(this->mDataFlags & DataFlags::REFCOUNTED))) { | 940 | 40.3k | return Assign(aStr, mozilla::fallible); | 941 | 40.3k | } | 942 | 18.4k | return Append(aStr.BeginReading(), aStr.Length(), mozilla::fallible); | 943 | 18.4k | } |
|
944 | | |
945 | | template <typename T> |
946 | | void |
947 | | nsTSubstring<T>::Append(const substring_tuple_type& aTuple) |
948 | 1.56k | { |
949 | 1.56k | if (MOZ_UNLIKELY(!Append(aTuple, mozilla::fallible))) { |
950 | 0 | AllocFailed(this->mLength + aTuple.Length()); |
951 | 0 | } |
952 | 1.56k | } nsTSubstring<char>::Append(nsTSubstringTuple<char> const&) Line | Count | Source | 948 | 1.56k | { | 949 | 1.56k | if (MOZ_UNLIKELY(!Append(aTuple, mozilla::fallible))) { | 950 | 0 | AllocFailed(this->mLength + aTuple.Length()); | 951 | 0 | } | 952 | 1.56k | } |
Unexecuted instantiation: nsTSubstring<char16_t>::Append(nsTSubstringTuple<char16_t> const&) |
953 | | |
954 | | template <typename T> |
955 | | bool |
956 | | nsTSubstring<T>::Append(const substring_tuple_type& aTuple, |
957 | | const fallible_t& aFallible) |
958 | 1.56k | { |
959 | 1.56k | size_type tupleLength = aTuple.Length(); |
960 | 1.56k | |
961 | 1.56k | if (MOZ_UNLIKELY(!tupleLength)) { |
962 | 0 | // Avoid undoing the effect of SetCapacity() if both |
963 | 0 | // mLength and tupleLength are zero. |
964 | 0 | return true; |
965 | 0 | } |
966 | 1.56k | |
967 | 1.56k | if (MOZ_UNLIKELY(aTuple.IsDependentOn(this->mData, this->mData + this->mLength))) { |
968 | 0 | return Append(string_type(aTuple), aFallible); |
969 | 0 | } |
970 | 1.56k | |
971 | 1.56k | size_type oldLen = this->mLength; |
972 | 1.56k | mozilla::CheckedInt<size_type> newLen(oldLen); |
973 | 1.56k | newLen += tupleLength; |
974 | 1.56k | if (MOZ_UNLIKELY(!newLen.isValid())) { |
975 | 0 | return false; |
976 | 0 | } |
977 | 1.56k | auto r = StartBulkWriteImpl(newLen.value(), oldLen, false); |
978 | 1.56k | if (MOZ_UNLIKELY(r.isErr())) { |
979 | 0 | return false; |
980 | 0 | } |
981 | 1.56k | aTuple.WriteTo(this->mData + oldLen, tupleLength); |
982 | 1.56k | FinishBulkWriteImpl(newLen.value()); |
983 | 1.56k | return true; |
984 | 1.56k | } nsTSubstring<char>::Append(nsTSubstringTuple<char> const&, std::nothrow_t const&) Line | Count | Source | 958 | 1.56k | { | 959 | 1.56k | size_type tupleLength = aTuple.Length(); | 960 | 1.56k | | 961 | 1.56k | if (MOZ_UNLIKELY(!tupleLength)) { | 962 | 0 | // Avoid undoing the effect of SetCapacity() if both | 963 | 0 | // mLength and tupleLength are zero. | 964 | 0 | return true; | 965 | 0 | } | 966 | 1.56k | | 967 | 1.56k | if (MOZ_UNLIKELY(aTuple.IsDependentOn(this->mData, this->mData + this->mLength))) { | 968 | 0 | return Append(string_type(aTuple), aFallible); | 969 | 0 | } | 970 | 1.56k | | 971 | 1.56k | size_type oldLen = this->mLength; | 972 | 1.56k | mozilla::CheckedInt<size_type> newLen(oldLen); | 973 | 1.56k | newLen += tupleLength; | 974 | 1.56k | if (MOZ_UNLIKELY(!newLen.isValid())) { | 975 | 0 | return false; | 976 | 0 | } | 977 | 1.56k | auto r = StartBulkWriteImpl(newLen.value(), oldLen, false); | 978 | 1.56k | if (MOZ_UNLIKELY(r.isErr())) { | 979 | 0 | return false; | 980 | 0 | } | 981 | 1.56k | aTuple.WriteTo(this->mData + oldLen, tupleLength); | 982 | 1.56k | FinishBulkWriteImpl(newLen.value()); | 983 | 1.56k | return true; | 984 | 1.56k | } |
Unexecuted instantiation: nsTSubstring<char16_t>::Append(nsTSubstringTuple<char16_t> const&, std::nothrow_t const&) |
985 | | |
986 | | template <typename T> |
987 | | void |
988 | | nsTSubstring<T>::SetCapacity(size_type aCapacity) |
989 | 2.57k | { |
990 | 2.57k | if (!SetCapacity(aCapacity, mozilla::fallible)) { |
991 | 0 | AllocFailed(aCapacity); |
992 | 0 | } |
993 | 2.57k | } nsTSubstring<char>::SetCapacity(unsigned int) Line | Count | Source | 989 | 2.57k | { | 990 | 2.57k | if (!SetCapacity(aCapacity, mozilla::fallible)) { | 991 | 0 | AllocFailed(aCapacity); | 992 | 0 | } | 993 | 2.57k | } |
Unexecuted instantiation: nsTSubstring<char16_t>::SetCapacity(unsigned int) |
994 | | |
995 | | template <typename T> |
996 | | bool |
997 | | nsTSubstring<T>::SetCapacity(size_type aCapacity, const fallible_t&) |
998 | 2.57k | { |
999 | 2.57k | size_type length = this->mLength; |
1000 | 2.57k | // This method can no longer be used to shorten the |
1001 | 2.57k | // logical length. |
1002 | 2.57k | size_type capacity = XPCOM_MAX(aCapacity, length); |
1003 | 2.57k | |
1004 | 2.57k | mozilla::Result<uint32_t, nsresult> r = |
1005 | 2.57k | StartBulkWriteImpl(capacity, length, true); |
1006 | 2.57k | if (r.isErr()) { |
1007 | 0 | return false; |
1008 | 0 | } |
1009 | 2.57k | |
1010 | 2.57k | if (MOZ_UNLIKELY(!capacity)) { |
1011 | 0 | // Zero capacity was requested on a zero-length |
1012 | 0 | // string. In this special case, we are pointing |
1013 | 0 | // to the special empty buffer, which is already |
1014 | 0 | // zero-terminated and not writable, so we must |
1015 | 0 | // not attempt to zero-terminate it. |
1016 | 0 | AssertValid(); |
1017 | 0 | return true; |
1018 | 0 | } |
1019 | 2.57k | |
1020 | 2.57k | // FinishBulkWriteImpl with argument zero releases |
1021 | 2.57k | // the heap-allocated buffer. However, SetCapacity() |
1022 | 2.57k | // is a special case that allows mLength to be zero |
1023 | 2.57k | // while a heap-allocated buffer exists. |
1024 | 2.57k | // By calling FinishBulkWriteImplImpl, we skip the |
1025 | 2.57k | // zero case handling that's inappropriate in the |
1026 | 2.57k | // SetCapacity() case. |
1027 | 2.57k | FinishBulkWriteImplImpl(length); |
1028 | 2.57k | return true; |
1029 | 2.57k | } nsTSubstring<char>::SetCapacity(unsigned int, std::nothrow_t const&) Line | Count | Source | 998 | 2.57k | { | 999 | 2.57k | size_type length = this->mLength; | 1000 | 2.57k | // This method can no longer be used to shorten the | 1001 | 2.57k | // logical length. | 1002 | 2.57k | size_type capacity = XPCOM_MAX(aCapacity, length); | 1003 | 2.57k | | 1004 | 2.57k | mozilla::Result<uint32_t, nsresult> r = | 1005 | 2.57k | StartBulkWriteImpl(capacity, length, true); | 1006 | 2.57k | if (r.isErr()) { | 1007 | 0 | return false; | 1008 | 0 | } | 1009 | 2.57k | | 1010 | 2.57k | if (MOZ_UNLIKELY(!capacity)) { | 1011 | 0 | // Zero capacity was requested on a zero-length | 1012 | 0 | // string. In this special case, we are pointing | 1013 | 0 | // to the special empty buffer, which is already | 1014 | 0 | // zero-terminated and not writable, so we must | 1015 | 0 | // not attempt to zero-terminate it. | 1016 | 0 | AssertValid(); | 1017 | 0 | return true; | 1018 | 0 | } | 1019 | 2.57k | | 1020 | 2.57k | // FinishBulkWriteImpl with argument zero releases | 1021 | 2.57k | // the heap-allocated buffer. However, SetCapacity() | 1022 | 2.57k | // is a special case that allows mLength to be zero | 1023 | 2.57k | // while a heap-allocated buffer exists. | 1024 | 2.57k | // By calling FinishBulkWriteImplImpl, we skip the | 1025 | 2.57k | // zero case handling that's inappropriate in the | 1026 | 2.57k | // SetCapacity() case. | 1027 | 2.57k | FinishBulkWriteImplImpl(length); | 1028 | 2.57k | return true; | 1029 | 2.57k | } |
Unexecuted instantiation: nsTSubstring<char16_t>::SetCapacity(unsigned int, std::nothrow_t const&) |
1030 | | |
1031 | | template <typename T> |
1032 | | void |
1033 | | nsTSubstring<T>::SetLength(size_type aLength) |
1034 | 4.54M | { |
1035 | 4.54M | if (!SetLength(aLength, mozilla::fallible)) { |
1036 | 0 | AllocFailed(aLength); |
1037 | 0 | } |
1038 | 4.54M | } nsTSubstring<char>::SetLength(unsigned int) Line | Count | Source | 1034 | 4.37M | { | 1035 | 4.37M | if (!SetLength(aLength, mozilla::fallible)) { | 1036 | 0 | AllocFailed(aLength); | 1037 | 0 | } | 1038 | 4.37M | } |
nsTSubstring<char16_t>::SetLength(unsigned int) Line | Count | Source | 1034 | 176k | { | 1035 | 176k | if (!SetLength(aLength, mozilla::fallible)) { | 1036 | 0 | AllocFailed(aLength); | 1037 | 0 | } | 1038 | 176k | } |
|
1039 | | |
1040 | | template <typename T> |
1041 | | bool |
1042 | | nsTSubstring<T>::SetLength(size_type aLength, const fallible_t& aFallible) |
1043 | 8.04M | { |
1044 | 8.04M | size_type preserve = XPCOM_MIN(aLength, this->mLength); |
1045 | 8.04M | mozilla::Result<uint32_t, nsresult> r = |
1046 | 8.04M | StartBulkWriteImpl(aLength, preserve, true); |
1047 | 8.04M | if (r.isErr()) { |
1048 | 0 | return false; |
1049 | 0 | } |
1050 | 8.04M | |
1051 | 8.04M | FinishBulkWriteImpl(aLength); |
1052 | 8.04M | |
1053 | 8.04M | return true; |
1054 | 8.04M | } nsTSubstring<char>::SetLength(unsigned int, std::nothrow_t const&) Line | Count | Source | 1043 | 7.67M | { | 1044 | 7.67M | size_type preserve = XPCOM_MIN(aLength, this->mLength); | 1045 | 7.67M | mozilla::Result<uint32_t, nsresult> r = | 1046 | 7.67M | StartBulkWriteImpl(aLength, preserve, true); | 1047 | 7.67M | if (r.isErr()) { | 1048 | 0 | return false; | 1049 | 0 | } | 1050 | 7.67M | | 1051 | 7.67M | FinishBulkWriteImpl(aLength); | 1052 | 7.67M | | 1053 | 7.67M | return true; | 1054 | 7.67M | } |
nsTSubstring<char16_t>::SetLength(unsigned int, std::nothrow_t const&) Line | Count | Source | 1043 | 366k | { | 1044 | 366k | size_type preserve = XPCOM_MIN(aLength, this->mLength); | 1045 | 366k | mozilla::Result<uint32_t, nsresult> r = | 1046 | 366k | StartBulkWriteImpl(aLength, preserve, true); | 1047 | 366k | if (r.isErr()) { | 1048 | 0 | return false; | 1049 | 0 | } | 1050 | 366k | | 1051 | 366k | FinishBulkWriteImpl(aLength); | 1052 | 366k | | 1053 | 366k | return true; | 1054 | 366k | } |
|
1055 | | |
1056 | | template<typename T> |
1057 | | void |
1058 | | nsTSubstring<T>::Truncate() |
1059 | 53.6M | { |
1060 | 53.6M | ::ReleaseData(this->mData, this->mDataFlags); |
1061 | 53.6M | SetToEmptyBuffer(); |
1062 | 53.6M | AssertValid(); |
1063 | 53.6M | } nsTSubstring<char>::Truncate() Line | Count | Source | 1059 | 45.2M | { | 1060 | 45.2M | ::ReleaseData(this->mData, this->mDataFlags); | 1061 | 45.2M | SetToEmptyBuffer(); | 1062 | 45.2M | AssertValid(); | 1063 | 45.2M | } |
nsTSubstring<char16_t>::Truncate() Line | Count | Source | 1059 | 8.41M | { | 1060 | 8.41M | ::ReleaseData(this->mData, this->mDataFlags); | 1061 | 8.41M | SetToEmptyBuffer(); | 1062 | 8.41M | AssertValid(); | 1063 | 8.41M | } |
|
1064 | | |
1065 | | template <typename T> |
1066 | | void |
1067 | | nsTSubstring<T>::SetIsVoid(bool aVal) |
1068 | 1.20k | { |
1069 | 1.20k | if (aVal) { |
1070 | 1.20k | Truncate(); |
1071 | 1.20k | this->mDataFlags |= DataFlags::VOIDED; |
1072 | 1.20k | } else { |
1073 | 0 | this->mDataFlags &= ~DataFlags::VOIDED; |
1074 | 0 | } |
1075 | 1.20k | } nsTSubstring<char>::SetIsVoid(bool) Line | Count | Source | 1068 | 1.20k | { | 1069 | 1.20k | if (aVal) { | 1070 | 1.20k | Truncate(); | 1071 | 1.20k | this->mDataFlags |= DataFlags::VOIDED; | 1072 | 1.20k | } else { | 1073 | 0 | this->mDataFlags &= ~DataFlags::VOIDED; | 1074 | 0 | } | 1075 | 1.20k | } |
Unexecuted instantiation: nsTSubstring<char16_t>::SetIsVoid(bool) |
1076 | | |
1077 | | namespace mozilla { |
1078 | | namespace detail { |
1079 | | |
1080 | | template <typename T> |
1081 | | typename nsTStringRepr<T>::char_type |
1082 | | nsTStringRepr<T>::First() const |
1083 | 1.27M | { |
1084 | 1.27M | MOZ_RELEASE_ASSERT(this->mLength > 0, "|First()| called on an empty string"); |
1085 | 1.27M | return this->mData[0]; |
1086 | 1.27M | } mozilla::detail::nsTStringRepr<char>::First() const Line | Count | Source | 1083 | 1.07M | { | 1084 | 1.07M | MOZ_RELEASE_ASSERT(this->mLength > 0, "|First()| called on an empty string"); | 1085 | 1.07M | return this->mData[0]; | 1086 | 1.07M | } |
mozilla::detail::nsTStringRepr<char16_t>::First() const Line | Count | Source | 1083 | 203k | { | 1084 | 203k | MOZ_RELEASE_ASSERT(this->mLength > 0, "|First()| called on an empty string"); | 1085 | 203k | return this->mData[0]; | 1086 | 203k | } |
|
1087 | | |
1088 | | template <typename T> |
1089 | | typename nsTStringRepr<T>::char_type |
1090 | | nsTStringRepr<T>::Last() const |
1091 | 8.59k | { |
1092 | 8.59k | MOZ_RELEASE_ASSERT(this->mLength > 0, "|Last()| called on an empty string"); |
1093 | 8.59k | return this->mData[this->mLength - 1]; |
1094 | 8.59k | } mozilla::detail::nsTStringRepr<char>::Last() const Line | Count | Source | 1091 | 2.50k | { | 1092 | 2.50k | MOZ_RELEASE_ASSERT(this->mLength > 0, "|Last()| called on an empty string"); | 1093 | 2.50k | return this->mData[this->mLength - 1]; | 1094 | 2.50k | } |
mozilla::detail::nsTStringRepr<char16_t>::Last() const Line | Count | Source | 1091 | 6.08k | { | 1092 | 6.08k | MOZ_RELEASE_ASSERT(this->mLength > 0, "|Last()| called on an empty string"); | 1093 | 6.08k | return this->mData[this->mLength - 1]; | 1094 | 6.08k | } |
|
1095 | | |
1096 | | template <typename T> |
1097 | | bool |
1098 | | nsTStringRepr<T>::Equals(const self_type& aStr) const |
1099 | 5.14M | { |
1100 | 5.14M | return this->mLength == aStr.mLength && |
1101 | 5.14M | char_traits::compare(this->mData, aStr.mData, this->mLength) == 0; |
1102 | 5.14M | } mozilla::detail::nsTStringRepr<char>::Equals(mozilla::detail::nsTStringRepr<char> const&) const Line | Count | Source | 1099 | 3.73M | { | 1100 | 3.73M | return this->mLength == aStr.mLength && | 1101 | 3.73M | char_traits::compare(this->mData, aStr.mData, this->mLength) == 0; | 1102 | 3.73M | } |
mozilla::detail::nsTStringRepr<char16_t>::Equals(mozilla::detail::nsTStringRepr<char16_t> const&) const Line | Count | Source | 1099 | 1.41M | { | 1100 | 1.41M | return this->mLength == aStr.mLength && | 1101 | 1.41M | char_traits::compare(this->mData, aStr.mData, this->mLength) == 0; | 1102 | 1.41M | } |
|
1103 | | |
1104 | | template <typename T> |
1105 | | bool |
1106 | | nsTStringRepr<T>::Equals(const self_type& aStr, |
1107 | | const comparator_type& aComp) const |
1108 | 22.9k | { |
1109 | 22.9k | return this->mLength == aStr.mLength && |
1110 | 22.9k | aComp(this->mData, aStr.mData, this->mLength, aStr.mLength) == 0; |
1111 | 22.9k | } mozilla::detail::nsTStringRepr<char>::Equals(mozilla::detail::nsTStringRepr<char> const&, nsTStringComparator<char> const&) const Line | Count | Source | 1108 | 6 | { | 1109 | 6 | return this->mLength == aStr.mLength && | 1110 | 6 | aComp(this->mData, aStr.mData, this->mLength, aStr.mLength) == 0; | 1111 | 6 | } |
mozilla::detail::nsTStringRepr<char16_t>::Equals(mozilla::detail::nsTStringRepr<char16_t> const&, nsTStringComparator<char16_t> const&) const Line | Count | Source | 1108 | 22.9k | { | 1109 | 22.9k | return this->mLength == aStr.mLength && | 1110 | 22.9k | aComp(this->mData, aStr.mData, this->mLength, aStr.mLength) == 0; | 1111 | 22.9k | } |
|
1112 | | |
1113 | | template <typename T> |
1114 | | bool |
1115 | | nsTStringRepr<T>::Equals(const substring_tuple_type& aTuple) const |
1116 | 0 | { |
1117 | 0 | return Equals(substring_type(aTuple)); |
1118 | 0 | } Unexecuted instantiation: mozilla::detail::nsTStringRepr<char>::Equals(nsTSubstringTuple<char> const&) const Unexecuted instantiation: mozilla::detail::nsTStringRepr<char16_t>::Equals(nsTSubstringTuple<char16_t> const&) const |
1119 | | |
1120 | | template <typename T> |
1121 | | bool |
1122 | | nsTStringRepr<T>::Equals(const substring_tuple_type& aTuple, |
1123 | | const comparator_type& aComp) const |
1124 | 0 | { |
1125 | 0 | return Equals(substring_type(aTuple), aComp); |
1126 | 0 | } Unexecuted instantiation: mozilla::detail::nsTStringRepr<char>::Equals(nsTSubstringTuple<char> const&, nsTStringComparator<char> const&) const Unexecuted instantiation: mozilla::detail::nsTStringRepr<char16_t>::Equals(nsTSubstringTuple<char16_t> const&, nsTStringComparator<char16_t> const&) const |
1127 | | |
1128 | | template <typename T> |
1129 | | bool |
1130 | | nsTStringRepr<T>::Equals(const char_type* aData) const |
1131 | 5.80M | { |
1132 | 5.80M | // unfortunately, some callers pass null :-( |
1133 | 5.80M | if (!aData) { |
1134 | 0 | MOZ_ASSERT_UNREACHABLE("null data pointer"); |
1135 | 0 | return this->mLength == 0; |
1136 | 0 | } |
1137 | 5.80M | |
1138 | 5.80M | // XXX avoid length calculation? |
1139 | 5.80M | size_type length = char_traits::length(aData); |
1140 | 5.80M | return this->mLength == length && |
1141 | 5.80M | char_traits::compare(this->mData, aData, this->mLength) == 0; |
1142 | 5.80M | } mozilla::detail::nsTStringRepr<char>::Equals(char const*) const Line | Count | Source | 1131 | 5.80M | { | 1132 | 5.80M | // unfortunately, some callers pass null :-( | 1133 | 5.80M | if (!aData) { | 1134 | 0 | MOZ_ASSERT_UNREACHABLE("null data pointer"); | 1135 | 0 | return this->mLength == 0; | 1136 | 0 | } | 1137 | 5.80M | | 1138 | 5.80M | // XXX avoid length calculation? | 1139 | 5.80M | size_type length = char_traits::length(aData); | 1140 | 5.80M | return this->mLength == length && | 1141 | 5.80M | char_traits::compare(this->mData, aData, this->mLength) == 0; | 1142 | 5.80M | } |
mozilla::detail::nsTStringRepr<char16_t>::Equals(char16_t const*) const Line | Count | Source | 1131 | 2.46k | { | 1132 | 2.46k | // unfortunately, some callers pass null :-( | 1133 | 2.46k | if (!aData) { | 1134 | 0 | MOZ_ASSERT_UNREACHABLE("null data pointer"); | 1135 | 0 | return this->mLength == 0; | 1136 | 0 | } | 1137 | 2.46k | | 1138 | 2.46k | // XXX avoid length calculation? | 1139 | 2.46k | size_type length = char_traits::length(aData); | 1140 | 2.46k | return this->mLength == length && | 1141 | 2.46k | char_traits::compare(this->mData, aData, this->mLength) == 0; | 1142 | 2.46k | } |
|
1143 | | |
1144 | | template <typename T> |
1145 | | bool |
1146 | | nsTStringRepr<T>::Equals(const char_type* aData, |
1147 | | const comparator_type& aComp) const |
1148 | 0 | { |
1149 | 0 | // unfortunately, some callers pass null :-( |
1150 | 0 | if (!aData) { |
1151 | 0 | MOZ_ASSERT_UNREACHABLE("null data pointer"); |
1152 | 0 | return this->mLength == 0; |
1153 | 0 | } |
1154 | 0 |
|
1155 | 0 | // XXX avoid length calculation? |
1156 | 0 | size_type length = char_traits::length(aData); |
1157 | 0 | return this->mLength == length && aComp(this->mData, aData, this->mLength, length) == 0; |
1158 | 0 | } Unexecuted instantiation: mozilla::detail::nsTStringRepr<char>::Equals(char const*, nsTStringComparator<char> const&) const Unexecuted instantiation: mozilla::detail::nsTStringRepr<char16_t>::Equals(char16_t const*, nsTStringComparator<char16_t> const&) const |
1159 | | |
1160 | | template <typename T> |
1161 | | bool |
1162 | | nsTStringRepr<T>::EqualsASCII(const char* aData, size_type aLen) const |
1163 | 13.0k | { |
1164 | 13.0k | return this->mLength == aLen && |
1165 | 13.0k | char_traits::compareASCII(this->mData, aData, aLen) == 0; |
1166 | 13.0k | } mozilla::detail::nsTStringRepr<char>::EqualsASCII(char const*, unsigned int) const Line | Count | Source | 1163 | 13.0k | { | 1164 | 13.0k | return this->mLength == aLen && | 1165 | 13.0k | char_traits::compareASCII(this->mData, aData, aLen) == 0; | 1166 | 13.0k | } |
Unexecuted instantiation: mozilla::detail::nsTStringRepr<char16_t>::EqualsASCII(char const*, unsigned int) const |
1167 | | |
1168 | | template <typename T> |
1169 | | bool |
1170 | | nsTStringRepr<T>::EqualsASCII(const char* aData) const |
1171 | 433k | { |
1172 | 433k | return char_traits::compareASCIINullTerminated(this->mData, this->mLength, aData) == 0; |
1173 | 433k | } mozilla::detail::nsTStringRepr<char>::EqualsASCII(char const*) const Line | Count | Source | 1171 | 866 | { | 1172 | 866 | return char_traits::compareASCIINullTerminated(this->mData, this->mLength, aData) == 0; | 1173 | 866 | } |
mozilla::detail::nsTStringRepr<char16_t>::EqualsASCII(char const*) const Line | Count | Source | 1171 | 432k | { | 1172 | 432k | return char_traits::compareASCIINullTerminated(this->mData, this->mLength, aData) == 0; | 1173 | 432k | } |
|
1174 | | |
1175 | | template <typename T> |
1176 | | bool |
1177 | | nsTStringRepr<T>::LowerCaseEqualsASCII(const char* aData, |
1178 | | size_type aLen) const |
1179 | 14.0M | { |
1180 | 14.0M | return this->mLength == aLen && |
1181 | 14.0M | char_traits::compareLowerCaseToASCII(this->mData, aData, aLen) == 0; |
1182 | 14.0M | } mozilla::detail::nsTStringRepr<char>::LowerCaseEqualsASCII(char const*, unsigned int) const Line | Count | Source | 1179 | 14.0M | { | 1180 | 14.0M | return this->mLength == aLen && | 1181 | 14.0M | char_traits::compareLowerCaseToASCII(this->mData, aData, aLen) == 0; | 1182 | 14.0M | } |
Unexecuted instantiation: mozilla::detail::nsTStringRepr<char16_t>::LowerCaseEqualsASCII(char const*, unsigned int) const |
1183 | | |
1184 | | template <typename T> |
1185 | | bool |
1186 | | nsTStringRepr<T>::LowerCaseEqualsASCII(const char* aData) const |
1187 | 8.15M | { |
1188 | 8.15M | return char_traits::compareLowerCaseToASCIINullTerminated(this->mData, |
1189 | 8.15M | this->mLength, |
1190 | 8.15M | aData) == 0; |
1191 | 8.15M | } mozilla::detail::nsTStringRepr<char>::LowerCaseEqualsASCII(char const*) const Line | Count | Source | 1187 | 81 | { | 1188 | 81 | return char_traits::compareLowerCaseToASCIINullTerminated(this->mData, | 1189 | 81 | this->mLength, | 1190 | 81 | aData) == 0; | 1191 | 81 | } |
mozilla::detail::nsTStringRepr<char16_t>::LowerCaseEqualsASCII(char const*) const Line | Count | Source | 1187 | 8.15M | { | 1188 | 8.15M | return char_traits::compareLowerCaseToASCIINullTerminated(this->mData, | 1189 | 8.15M | this->mLength, | 1190 | 8.15M | aData) == 0; | 1191 | 8.15M | } |
|
1192 | | |
1193 | | template <typename T> |
1194 | | typename nsTStringRepr<T>::size_type |
1195 | | nsTStringRepr<T>::CountChar(char_type aChar) const |
1196 | 18 | { |
1197 | 18 | const char_type* start = this->mData; |
1198 | 18 | const char_type* end = this->mData + this->mLength; |
1199 | 18 | |
1200 | 18 | return NS_COUNT(start, end, aChar); |
1201 | 18 | } mozilla::detail::nsTStringRepr<char>::CountChar(char) const Line | Count | Source | 1196 | 18 | { | 1197 | 18 | const char_type* start = this->mData; | 1198 | 18 | const char_type* end = this->mData + this->mLength; | 1199 | 18 | | 1200 | 18 | return NS_COUNT(start, end, aChar); | 1201 | 18 | } |
Unexecuted instantiation: mozilla::detail::nsTStringRepr<char16_t>::CountChar(char16_t) const |
1202 | | |
1203 | | template <typename T> |
1204 | | int32_t |
1205 | | nsTStringRepr<T>::FindChar(char_type aChar, index_type aOffset) const |
1206 | 7.97M | { |
1207 | 7.97M | if (aOffset < this->mLength) { |
1208 | 7.18M | const char_type* result = char_traits::find(this->mData + aOffset, |
1209 | 7.18M | this->mLength - aOffset, aChar); |
1210 | 7.18M | if (result) { |
1211 | 1.94M | return result - this->mData; |
1212 | 1.94M | } |
1213 | 6.02M | } |
1214 | 6.02M | return -1; |
1215 | 6.02M | } mozilla::detail::nsTStringRepr<char>::FindChar(char, unsigned int) const Line | Count | Source | 1206 | 7.96M | { | 1207 | 7.96M | if (aOffset < this->mLength) { | 1208 | 7.17M | const char_type* result = char_traits::find(this->mData + aOffset, | 1209 | 7.17M | this->mLength - aOffset, aChar); | 1210 | 7.17M | if (result) { | 1211 | 1.94M | return result - this->mData; | 1212 | 1.94M | } | 1213 | 6.02M | } | 1214 | 6.02M | return -1; | 1215 | 6.02M | } |
mozilla::detail::nsTStringRepr<char16_t>::FindChar(char16_t, unsigned int) const Line | Count | Source | 1206 | 3.78k | { | 1207 | 3.78k | if (aOffset < this->mLength) { | 1208 | 3.68k | const char_type* result = char_traits::find(this->mData + aOffset, | 1209 | 3.68k | this->mLength - aOffset, aChar); | 1210 | 3.68k | if (result) { | 1211 | 3.01k | return result - this->mData; | 1212 | 3.01k | } | 1213 | 769 | } | 1214 | 769 | return -1; | 1215 | 769 | } |
|
1216 | | |
1217 | | } // namespace detail |
1218 | | } // namespace mozilla |
1219 | | |
1220 | | template <typename T> |
1221 | | void |
1222 | | nsTSubstring<T>::StripChar(char_type aChar) |
1223 | 0 | { |
1224 | 0 | if (this->mLength == 0) { |
1225 | 0 | return; |
1226 | 0 | } |
1227 | 0 | |
1228 | 0 | if (!EnsureMutable()) { // XXX do this lazily? |
1229 | 0 | AllocFailed(this->mLength); |
1230 | 0 | } |
1231 | 0 |
|
1232 | 0 | // XXX(darin): this code should defer writing until necessary. |
1233 | 0 |
|
1234 | 0 | char_type* to = this->mData; |
1235 | 0 | char_type* from = this->mData; |
1236 | 0 | char_type* end = this->mData + this->mLength; |
1237 | 0 |
|
1238 | 0 | while (from < end) { |
1239 | 0 | char_type theChar = *from++; |
1240 | 0 | if (aChar != theChar) { |
1241 | 0 | *to++ = theChar; |
1242 | 0 | } |
1243 | 0 | } |
1244 | 0 | *to = char_type(0); // add the null |
1245 | 0 | this->mLength = to - this->mData; |
1246 | 0 | } Unexecuted instantiation: nsTSubstring<char>::StripChar(char) Unexecuted instantiation: nsTSubstring<char16_t>::StripChar(char16_t) |
1247 | | |
1248 | | template <typename T> |
1249 | | void |
1250 | | nsTSubstring<T>::StripChars(const char_type* aChars) |
1251 | 1 | { |
1252 | 1 | if (this->mLength == 0) { |
1253 | 0 | return; |
1254 | 0 | } |
1255 | 1 | |
1256 | 1 | if (!EnsureMutable()) { // XXX do this lazily? |
1257 | 0 | AllocFailed(this->mLength); |
1258 | 0 | } |
1259 | 1 | |
1260 | 1 | // XXX(darin): this code should defer writing until necessary. |
1261 | 1 | |
1262 | 1 | char_type* to = this->mData; |
1263 | 1 | char_type* from = this->mData; |
1264 | 1 | char_type* end = this->mData + this->mLength; |
1265 | 1 | |
1266 | 8 | while (from < end) { |
1267 | 7 | char_type theChar = *from++; |
1268 | 7 | const char_type* test = aChars; |
1269 | 7 | |
1270 | 133 | for (; *test && *test != theChar; ++test); |
1271 | 7 | |
1272 | 7 | if (!*test) { |
1273 | 7 | // Not stripped, copy this char. |
1274 | 7 | *to++ = theChar; |
1275 | 7 | } |
1276 | 7 | } |
1277 | 1 | *to = char_type(0); // add the null |
1278 | 1 | this->mLength = to - this->mData; |
1279 | 1 | } nsTSubstring<char>::StripChars(char const*) Line | Count | Source | 1251 | 1 | { | 1252 | 1 | if (this->mLength == 0) { | 1253 | 0 | return; | 1254 | 0 | } | 1255 | 1 | | 1256 | 1 | if (!EnsureMutable()) { // XXX do this lazily? | 1257 | 0 | AllocFailed(this->mLength); | 1258 | 0 | } | 1259 | 1 | | 1260 | 1 | // XXX(darin): this code should defer writing until necessary. | 1261 | 1 | | 1262 | 1 | char_type* to = this->mData; | 1263 | 1 | char_type* from = this->mData; | 1264 | 1 | char_type* end = this->mData + this->mLength; | 1265 | 1 | | 1266 | 8 | while (from < end) { | 1267 | 7 | char_type theChar = *from++; | 1268 | 7 | const char_type* test = aChars; | 1269 | 7 | | 1270 | 133 | for (; *test && *test != theChar; ++test); | 1271 | 7 | | 1272 | 7 | if (!*test) { | 1273 | 7 | // Not stripped, copy this char. | 1274 | 7 | *to++ = theChar; | 1275 | 7 | } | 1276 | 7 | } | 1277 | 1 | *to = char_type(0); // add the null | 1278 | 1 | this->mLength = to - this->mData; | 1279 | 1 | } |
Unexecuted instantiation: nsTSubstring<char16_t>::StripChars(char16_t const*) |
1280 | | |
1281 | | template <typename T> |
1282 | | void |
1283 | | nsTSubstring<T>::StripTaggedASCII(const ASCIIMaskArray& aToStrip) |
1284 | 3.91M | { |
1285 | 3.91M | if (this->mLength == 0) { |
1286 | 0 | return; |
1287 | 0 | } |
1288 | 3.91M | |
1289 | 3.91M | if (!EnsureMutable()) { |
1290 | 0 | AllocFailed(this->mLength); |
1291 | 0 | } |
1292 | 3.91M | |
1293 | 3.91M | char_type* to = this->mData; |
1294 | 3.91M | char_type* from = this->mData; |
1295 | 3.91M | char_type* end = this->mData + this->mLength; |
1296 | 3.91M | |
1297 | 19.3M | while (from < end) { |
1298 | 15.4M | uint32_t theChar = (uint32_t)*from++; |
1299 | 15.4M | // Replacing this with a call to ASCIIMask::IsMasked |
1300 | 15.4M | // regresses performance somewhat, so leaving it inlined. |
1301 | 15.4M | if (!mozilla::ASCIIMask::IsMasked(aToStrip, theChar)) { |
1302 | 15.4M | // Not stripped, copy this char. |
1303 | 15.4M | *to++ = (char_type)theChar; |
1304 | 15.4M | } |
1305 | 15.4M | } |
1306 | 3.91M | *to = char_type(0); // add the null |
1307 | 3.91M | this->mLength = to - this->mData; |
1308 | 3.91M | } nsTSubstring<char>::StripTaggedASCII(std::__1::array<bool, 128ul> const&) Line | Count | Source | 1284 | 3.91M | { | 1285 | 3.91M | if (this->mLength == 0) { | 1286 | 0 | return; | 1287 | 0 | } | 1288 | 3.91M | | 1289 | 3.91M | if (!EnsureMutable()) { | 1290 | 0 | AllocFailed(this->mLength); | 1291 | 0 | } | 1292 | 3.91M | | 1293 | 3.91M | char_type* to = this->mData; | 1294 | 3.91M | char_type* from = this->mData; | 1295 | 3.91M | char_type* end = this->mData + this->mLength; | 1296 | 3.91M | | 1297 | 19.3M | while (from < end) { | 1298 | 15.4M | uint32_t theChar = (uint32_t)*from++; | 1299 | 15.4M | // Replacing this with a call to ASCIIMask::IsMasked | 1300 | 15.4M | // regresses performance somewhat, so leaving it inlined. | 1301 | 15.4M | if (!mozilla::ASCIIMask::IsMasked(aToStrip, theChar)) { | 1302 | 15.4M | // Not stripped, copy this char. | 1303 | 15.4M | *to++ = (char_type)theChar; | 1304 | 15.4M | } | 1305 | 15.4M | } | 1306 | 3.91M | *to = char_type(0); // add the null | 1307 | 3.91M | this->mLength = to - this->mData; | 1308 | 3.91M | } |
Unexecuted instantiation: nsTSubstring<char16_t>::StripTaggedASCII(std::__1::array<bool, 128ul> const&) |
1309 | | |
1310 | | template <typename T> |
1311 | | void |
1312 | | nsTSubstring<T>::StripCRLF() |
1313 | 0 | { |
1314 | 0 | // Expanding this call to copy the code from StripTaggedASCII |
1315 | 0 | // instead of just calling it does somewhat help with performance |
1316 | 0 | // but it is not worth it given the duplicated code. |
1317 | 0 | StripTaggedASCII(mozilla::ASCIIMask::MaskCRLF()); |
1318 | 0 | } Unexecuted instantiation: nsTSubstring<char>::StripCRLF() Unexecuted instantiation: nsTSubstring<char16_t>::StripCRLF() |
1319 | | |
1320 | | template <typename T> |
1321 | | struct MOZ_STACK_CLASS PrintfAppend : public mozilla::PrintfTarget |
1322 | | { |
1323 | | explicit PrintfAppend(nsTSubstring<T>* aString) |
1324 | | : mString(aString) |
1325 | 4.41k | { |
1326 | 4.41k | } PrintfAppend<char>::PrintfAppend(nsTSubstring<char>*) Line | Count | Source | 1325 | 4.41k | { | 1326 | 4.41k | } |
Unexecuted instantiation: PrintfAppend<char16_t>::PrintfAppend(nsTSubstring<char16_t>*) |
1327 | | |
1328 | 28.3k | bool append(const char* aStr, size_t aLen) override { |
1329 | 28.3k | if (aLen == 0) { |
1330 | 0 | return true; |
1331 | 0 | } |
1332 | 28.3k | |
1333 | 28.3k | mString->AppendASCII(aStr, aLen); |
1334 | 28.3k | return true; |
1335 | 28.3k | } PrintfAppend<char>::append(char const*, unsigned long) Line | Count | Source | 1328 | 28.3k | bool append(const char* aStr, size_t aLen) override { | 1329 | 28.3k | if (aLen == 0) { | 1330 | 0 | return true; | 1331 | 0 | } | 1332 | 28.3k | | 1333 | 28.3k | mString->AppendASCII(aStr, aLen); | 1334 | 28.3k | return true; | 1335 | 28.3k | } |
Unexecuted instantiation: PrintfAppend<char16_t>::append(char const*, unsigned long) |
1336 | | |
1337 | | private: |
1338 | | |
1339 | | nsTSubstring<T>* mString; |
1340 | | }; |
1341 | | |
1342 | | template <typename T> |
1343 | | void |
1344 | | nsTSubstring<T>::AppendPrintf(const char* aFormat, ...) |
1345 | 404 | { |
1346 | 404 | PrintfAppend<T> appender(this); |
1347 | 404 | va_list ap; |
1348 | 404 | va_start(ap, aFormat); |
1349 | 404 | bool r = appender.vprint(aFormat, ap); |
1350 | 404 | if (!r) { |
1351 | 0 | MOZ_CRASH("Allocation or other failure in PrintfTarget::print"); |
1352 | 0 | } |
1353 | 404 | va_end(ap); |
1354 | 404 | } nsTSubstring<char>::AppendPrintf(char const*, ...) Line | Count | Source | 1345 | 404 | { | 1346 | 404 | PrintfAppend<T> appender(this); | 1347 | 404 | va_list ap; | 1348 | 404 | va_start(ap, aFormat); | 1349 | 404 | bool r = appender.vprint(aFormat, ap); | 1350 | 404 | if (!r) { | 1351 | 0 | MOZ_CRASH("Allocation or other failure in PrintfTarget::print"); | 1352 | 0 | } | 1353 | 404 | va_end(ap); | 1354 | 404 | } |
Unexecuted instantiation: nsTSubstring<char16_t>::AppendPrintf(char const*, ...) |
1355 | | |
1356 | | template <typename T> |
1357 | | void |
1358 | | nsTSubstring<T>::AppendPrintf(const char* aFormat, va_list aAp) |
1359 | 4.00k | { |
1360 | 4.00k | PrintfAppend<T> appender(this); |
1361 | 4.00k | bool r = appender.vprint(aFormat, aAp); |
1362 | 4.00k | if (!r) { |
1363 | 0 | MOZ_CRASH("Allocation or other failure in PrintfTarget::print"); |
1364 | 0 | } |
1365 | 4.00k | } nsTSubstring<char>::AppendPrintf(char const*, __va_list_tag*) Line | Count | Source | 1359 | 4.00k | { | 1360 | 4.00k | PrintfAppend<T> appender(this); | 1361 | 4.00k | bool r = appender.vprint(aFormat, aAp); | 1362 | 4.00k | if (!r) { | 1363 | 0 | MOZ_CRASH("Allocation or other failure in PrintfTarget::print"); | 1364 | 0 | } | 1365 | 4.00k | } |
Unexecuted instantiation: nsTSubstring<char16_t>::AppendPrintf(char const*, __va_list_tag*) |
1366 | | |
1367 | | // Returns the length of the formatted aDouble in aBuf. |
1368 | | static int |
1369 | | FormatWithoutTrailingZeros(char (&aBuf)[40], double aDouble, |
1370 | | int aPrecision) |
1371 | 0 | { |
1372 | 0 | static const DoubleToStringConverter converter(DoubleToStringConverter::UNIQUE_ZERO | |
1373 | 0 | DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN, |
1374 | 0 | "Infinity", |
1375 | 0 | "NaN", |
1376 | 0 | 'e', |
1377 | 0 | -6, 21, |
1378 | 0 | 6, 1); |
1379 | 0 | double_conversion::StringBuilder builder(aBuf, sizeof(aBuf)); |
1380 | 0 | bool exponential_notation = false; |
1381 | 0 | converter.ToPrecision(aDouble, aPrecision, &exponential_notation, &builder); |
1382 | 0 | int length = builder.position(); |
1383 | 0 | char* formattedDouble = builder.Finalize(); |
1384 | 0 |
|
1385 | 0 | // If we have a shorter string than aPrecision, it means we have a special |
1386 | 0 | // value (NaN or Infinity). All other numbers will be formatted with at |
1387 | 0 | // least aPrecision digits. |
1388 | 0 | if (length <= aPrecision) { |
1389 | 0 | return length; |
1390 | 0 | } |
1391 | 0 | |
1392 | 0 | char* end = formattedDouble + length; |
1393 | 0 | char* decimalPoint = strchr(aBuf, '.'); |
1394 | 0 | // No trailing zeros to remove. |
1395 | 0 | if (!decimalPoint) { |
1396 | 0 | return length; |
1397 | 0 | } |
1398 | 0 | |
1399 | 0 | if (MOZ_UNLIKELY(exponential_notation)) { |
1400 | 0 | // We need to check for cases like 1.00000e-10 (yes, this is |
1401 | 0 | // disgusting). |
1402 | 0 | char* exponent = end - 1; |
1403 | 0 | for (; ; --exponent) { |
1404 | 0 | if (*exponent == 'e') { |
1405 | 0 | break; |
1406 | 0 | } |
1407 | 0 | } |
1408 | 0 | char* zerosBeforeExponent = exponent - 1; |
1409 | 0 | for (; zerosBeforeExponent != decimalPoint; --zerosBeforeExponent) { |
1410 | 0 | if (*zerosBeforeExponent != '0') { |
1411 | 0 | break; |
1412 | 0 | } |
1413 | 0 | } |
1414 | 0 | if (zerosBeforeExponent == decimalPoint) { |
1415 | 0 | --zerosBeforeExponent; |
1416 | 0 | } |
1417 | 0 | // Slide the exponent to the left over the trailing zeros. Don't |
1418 | 0 | // worry about copying the trailing NUL character. |
1419 | 0 | size_t exponentSize = end - exponent; |
1420 | 0 | memmove(zerosBeforeExponent + 1, exponent, exponentSize); |
1421 | 0 | length -= exponent - (zerosBeforeExponent + 1); |
1422 | 0 | } else { |
1423 | 0 | char* trailingZeros = end - 1; |
1424 | 0 | for (; trailingZeros != decimalPoint; --trailingZeros) { |
1425 | 0 | if (*trailingZeros != '0') { |
1426 | 0 | break; |
1427 | 0 | } |
1428 | 0 | } |
1429 | 0 | if (trailingZeros == decimalPoint) { |
1430 | 0 | --trailingZeros; |
1431 | 0 | } |
1432 | 0 | length -= end - (trailingZeros + 1); |
1433 | 0 | } |
1434 | 0 |
|
1435 | 0 | return length; |
1436 | 0 | } |
1437 | | |
1438 | | template <typename T> |
1439 | | void |
1440 | | nsTSubstring<T>::AppendFloat(float aFloat) |
1441 | 0 | { |
1442 | 0 | char buf[40]; |
1443 | 0 | int length = FormatWithoutTrailingZeros(buf, aFloat, 6); |
1444 | 0 | AppendASCII(buf, length); |
1445 | 0 | } Unexecuted instantiation: nsTSubstring<char>::AppendFloat(float) Unexecuted instantiation: nsTSubstring<char16_t>::AppendFloat(float) |
1446 | | |
1447 | | template <typename T> |
1448 | | void |
1449 | | nsTSubstring<T>::AppendFloat(double aFloat) |
1450 | 0 | { |
1451 | 0 | char buf[40]; |
1452 | 0 | int length = FormatWithoutTrailingZeros(buf, aFloat, 15); |
1453 | 0 | AppendASCII(buf, length); |
1454 | 0 | } Unexecuted instantiation: nsTSubstring<char>::AppendFloat(double) Unexecuted instantiation: nsTSubstring<char16_t>::AppendFloat(double) |
1455 | | |
1456 | | template <typename T> |
1457 | | size_t |
1458 | | nsTSubstring<T>::SizeOfExcludingThisIfUnshared( |
1459 | | mozilla::MallocSizeOf aMallocSizeOf) const |
1460 | 0 | { |
1461 | 0 | if (this->mDataFlags & DataFlags::REFCOUNTED) { |
1462 | 0 | return nsStringBuffer::FromData(this->mData)-> |
1463 | 0 | SizeOfIncludingThisIfUnshared(aMallocSizeOf); |
1464 | 0 | } |
1465 | 0 | if (this->mDataFlags & DataFlags::OWNED) { |
1466 | 0 | return aMallocSizeOf(this->mData); |
1467 | 0 | } |
1468 | 0 | |
1469 | 0 | // If we reach here, exactly one of the following must be true: |
1470 | 0 | // - DataFlags::VOIDED is set, and this->mData points to sEmptyBuffer; |
1471 | 0 | // - DataFlags::INLINE is set, and this->mData points to a buffer within a |
1472 | 0 | // string object (e.g. nsAutoString); |
1473 | 0 | // - None of DataFlags::REFCOUNTED, DataFlags::OWNED, DataFlags::INLINE is set, |
1474 | 0 | // and this->mData points to a buffer owned by something else. |
1475 | 0 | // |
1476 | 0 | // In all three cases, we don't measure it. |
1477 | 0 | return 0; |
1478 | 0 | } Unexecuted instantiation: nsTSubstring<char>::SizeOfExcludingThisIfUnshared(unsigned long (*)(void const*)) const Unexecuted instantiation: nsTSubstring<char16_t>::SizeOfExcludingThisIfUnshared(unsigned long (*)(void const*)) const |
1479 | | |
1480 | | template <typename T> |
1481 | | size_t |
1482 | | nsTSubstring<T>::SizeOfExcludingThisEvenIfShared( |
1483 | | mozilla::MallocSizeOf aMallocSizeOf) const |
1484 | 0 | { |
1485 | 0 | // This is identical to SizeOfExcludingThisIfUnshared except for the |
1486 | 0 | // DataFlags::REFCOUNTED case. |
1487 | 0 | if (this->mDataFlags & DataFlags::REFCOUNTED) { |
1488 | 0 | return nsStringBuffer::FromData(this->mData)-> |
1489 | 0 | SizeOfIncludingThisEvenIfShared(aMallocSizeOf); |
1490 | 0 | } |
1491 | 0 | if (this->mDataFlags & DataFlags::OWNED) { |
1492 | 0 | return aMallocSizeOf(this->mData); |
1493 | 0 | } |
1494 | 0 | return 0; |
1495 | 0 | } Unexecuted instantiation: nsTSubstring<char>::SizeOfExcludingThisEvenIfShared(unsigned long (*)(void const*)) const Unexecuted instantiation: nsTSubstring<char16_t>::SizeOfExcludingThisEvenIfShared(unsigned long (*)(void const*)) const |
1496 | | |
1497 | | template <typename T> |
1498 | | size_t |
1499 | | nsTSubstring<T>::SizeOfIncludingThisIfUnshared( |
1500 | | mozilla::MallocSizeOf aMallocSizeOf) const |
1501 | 0 | { |
1502 | 0 | return aMallocSizeOf(this) + SizeOfExcludingThisIfUnshared(aMallocSizeOf); |
1503 | 0 | } Unexecuted instantiation: nsTSubstring<char>::SizeOfIncludingThisIfUnshared(unsigned long (*)(void const*)) const Unexecuted instantiation: nsTSubstring<char16_t>::SizeOfIncludingThisIfUnshared(unsigned long (*)(void const*)) const |
1504 | | |
1505 | | template <typename T> |
1506 | | size_t |
1507 | | nsTSubstring<T>::SizeOfIncludingThisEvenIfShared( |
1508 | | mozilla::MallocSizeOf aMallocSizeOf) const |
1509 | 0 | { |
1510 | 0 | return aMallocSizeOf(this) + SizeOfExcludingThisEvenIfShared(aMallocSizeOf); |
1511 | 0 | } Unexecuted instantiation: nsTSubstring<char>::SizeOfIncludingThisEvenIfShared(unsigned long (*)(void const*)) const Unexecuted instantiation: nsTSubstring<char16_t>::SizeOfIncludingThisEvenIfShared(unsigned long (*)(void const*)) const |
1512 | | |
1513 | | template <typename T> |
1514 | | inline |
1515 | | nsTSubstringSplitter<T>::nsTSubstringSplitter( |
1516 | | const nsTSubstring<T>* aStr, char_type aDelim) |
1517 | | : mStr(aStr) |
1518 | | , mArray(nullptr) |
1519 | | , mDelim(aDelim) |
1520 | 24 | { |
1521 | 24 | if (mStr->IsEmpty()) { |
1522 | 6 | mArraySize = 0; |
1523 | 6 | return; |
1524 | 6 | } |
1525 | 18 | |
1526 | 18 | size_type delimCount = mStr->CountChar(aDelim); |
1527 | 18 | mArraySize = delimCount + 1; |
1528 | 18 | mArray.reset(new nsTDependentSubstring<T>[mArraySize]); |
1529 | 18 | |
1530 | 18 | size_t seenParts = 0; |
1531 | 18 | size_type start = 0; |
1532 | 36 | do { |
1533 | 36 | MOZ_ASSERT(seenParts < mArraySize); |
1534 | 36 | int32_t offset = mStr->FindChar(aDelim, start); |
1535 | 36 | if (offset != -1) { |
1536 | 18 | size_type length = static_cast<size_type>(offset) - start; |
1537 | 18 | mArray[seenParts++].Rebind(mStr->Data() + start, length); |
1538 | 18 | start = static_cast<size_type>(offset) + 1; |
1539 | 18 | } else { |
1540 | 18 | // Get the remainder |
1541 | 18 | mArray[seenParts++].Rebind(mStr->Data() + start, mStr->Length() - start); |
1542 | 18 | break; |
1543 | 18 | } |
1544 | 18 | } while (start < mStr->Length()); |
1545 | 18 | } nsTSubstringSplitter<char>::nsTSubstringSplitter(nsTSubstring<char> const*, char) Line | Count | Source | 1520 | 24 | { | 1521 | 24 | if (mStr->IsEmpty()) { | 1522 | 6 | mArraySize = 0; | 1523 | 6 | return; | 1524 | 6 | } | 1525 | 18 | | 1526 | 18 | size_type delimCount = mStr->CountChar(aDelim); | 1527 | 18 | mArraySize = delimCount + 1; | 1528 | 18 | mArray.reset(new nsTDependentSubstring<T>[mArraySize]); | 1529 | 18 | | 1530 | 18 | size_t seenParts = 0; | 1531 | 18 | size_type start = 0; | 1532 | 36 | do { | 1533 | 36 | MOZ_ASSERT(seenParts < mArraySize); | 1534 | 36 | int32_t offset = mStr->FindChar(aDelim, start); | 1535 | 36 | if (offset != -1) { | 1536 | 18 | size_type length = static_cast<size_type>(offset) - start; | 1537 | 18 | mArray[seenParts++].Rebind(mStr->Data() + start, length); | 1538 | 18 | start = static_cast<size_type>(offset) + 1; | 1539 | 18 | } else { | 1540 | 18 | // Get the remainder | 1541 | 18 | mArray[seenParts++].Rebind(mStr->Data() + start, mStr->Length() - start); | 1542 | 18 | break; | 1543 | 18 | } | 1544 | 18 | } while (start < mStr->Length()); | 1545 | 18 | } |
Unexecuted instantiation: nsTSubstringSplitter<char16_t>::nsTSubstringSplitter(nsTSubstring<char16_t> const*, char16_t) |
1546 | | |
1547 | | template <typename T> |
1548 | | nsTSubstringSplitter<T> |
1549 | | nsTSubstring<T>::Split(const char_type aChar) const |
1550 | 24 | { |
1551 | 24 | return nsTSubstringSplitter<T>(this, aChar); |
1552 | 24 | } nsTSubstring<char>::Split(char) const Line | Count | Source | 1550 | 24 | { | 1551 | 24 | return nsTSubstringSplitter<T>(this, aChar); | 1552 | 24 | } |
Unexecuted instantiation: nsTSubstring<char16_t>::Split(char16_t) const |
1553 | | |
1554 | | template <typename T> |
1555 | | const nsTDependentSubstring<T>& |
1556 | | nsTSubstringSplitter<T>::nsTSubstringSplit_Iter::operator* () const |
1557 | 36 | { |
1558 | 36 | return mObj.Get(mPos); |
1559 | 36 | } nsTSubstringSplitter<char>::nsTSubstringSplit_Iter::operator*() const Line | Count | Source | 1557 | 36 | { | 1558 | 36 | return mObj.Get(mPos); | 1559 | 36 | } |
Unexecuted instantiation: nsTSubstringSplitter<char16_t>::nsTSubstringSplit_Iter::operator*() const |
1560 | | |
1561 | | // Common logic for nsTSubstring<T>::ToInteger and nsTSubstring<T>::ToInteger64. |
1562 | | template<typename T, typename int_type> |
1563 | | int_type |
1564 | | ToIntegerCommon(const nsTSubstring<T>& aSrc, nsresult* aErrorCode, uint32_t aRadix) |
1565 | 1.25k | { |
1566 | 1.25k | MOZ_ASSERT(aRadix == 10 || aRadix == 16); |
1567 | 1.25k | |
1568 | 1.25k | // Initial value, override if we find an integer. |
1569 | 1.25k | *aErrorCode = NS_ERROR_ILLEGAL_VALUE; |
1570 | 1.25k | |
1571 | 1.25k | // Begin by skipping over leading chars that shouldn't be part of the number. |
1572 | 1.25k | auto cp = aSrc.BeginReading(); |
1573 | 1.25k | auto endcp = aSrc.EndReading(); |
1574 | 1.25k | bool negate = false; |
1575 | 1.25k | bool done = false; |
1576 | 1.25k | |
1577 | 1.25k | // NB: For backwards compatibility I'm not going to change this logic but |
1578 | 1.25k | // it seems really odd. Previously there was logic to auto-detect the |
1579 | 1.25k | // radix if kAutoDetect was passed in. In practice this value was never |
1580 | 1.25k | // used, so it pretended to auto detect and skipped some preceding |
1581 | 1.25k | // letters (excluding valid hex digits) but never used the result. |
1582 | 1.25k | // |
1583 | 1.25k | // For example if you pass in "Get the number: 10", aRadix = 10 we'd |
1584 | 1.25k | // skip the 'G', and then fail to parse "et the number: 10". If aRadix = |
1585 | 1.25k | // 16 we'd skip the 'G', and parse just 'e' returning 14. |
1586 | 12.8k | while ((cp < endcp) && (!done)) { |
1587 | 11.5k | switch (*cp++) { |
1588 | 11.5k | // clang-format off |
1589 | 11.5k | case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': |
1590 | 1.24k | case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': |
1591 | 1.24k | case '0': case '1': case '2': case '3': case '4': |
1592 | 1.24k | case '5': case '6': case '7': case '8': case '9': |
1593 | 1.24k | done = true; |
1594 | 1.24k | break; |
1595 | 1.24k | // clang-format on |
1596 | 1.24k | case '-': |
1597 | 276 | negate = true; |
1598 | 276 | break; |
1599 | 10.0k | default: |
1600 | 10.0k | break; |
1601 | 11.5k | } |
1602 | 11.5k | } |
1603 | 1.25k | |
1604 | 1.25k | if (!done) { |
1605 | 12 | // No base 16 or base 10 digits were found. |
1606 | 12 | return 0; |
1607 | 12 | } |
1608 | 1.24k | |
1609 | 1.24k | // Step back. |
1610 | 1.24k | cp--; |
1611 | 1.24k | |
1612 | 1.24k | mozilla::CheckedInt<int_type> result; |
1613 | 1.24k | |
1614 | 1.24k | // Now iterate the numeric chars and build our result. |
1615 | 4.64k | while (cp < endcp) { |
1616 | 3.93k | auto theChar = *cp++; |
1617 | 3.93k | if (('0' <= theChar) && (theChar <= '9')) { |
1618 | 3.42k | result = (aRadix * result) + (theChar - '0'); |
1619 | 3.42k | } else if ((theChar >= 'A') && (theChar <= 'F')) { |
1620 | 0 | if (10 == aRadix) { |
1621 | 0 | // Invalid base 10 digit, error out. |
1622 | 0 | return 0; |
1623 | 0 | } else { |
1624 | 0 | result = (aRadix * result) + ((theChar - 'A') + 10); |
1625 | 0 | } |
1626 | 511 | } else if ((theChar >= 'a') && (theChar <= 'f')) { |
1627 | 267 | if (10 == aRadix) { |
1628 | 267 | // Invalid base 10 digit, error out. |
1629 | 267 | return 0; |
1630 | 267 | } else { |
1631 | 0 | result = (aRadix * result) + ((theChar - 'a') + 10); |
1632 | 0 | } |
1633 | 267 | } else if ((('X' == theChar) || ('x' == theChar)) && result == 0) { |
1634 | 0 | // For some reason we support a leading 'x' regardless of radix. For |
1635 | 0 | // example: "000000x500", aRadix = 10 would be parsed as 500 rather |
1636 | 0 | // than 0. |
1637 | 0 | continue; |
1638 | 244 | } else { |
1639 | 244 | // We've encountered a char that's not a legal number or sign and we can |
1640 | 244 | // terminate processing. |
1641 | 244 | break; |
1642 | 244 | } |
1643 | 3.42k | |
1644 | 3.42k | if (!result.isValid()) { |
1645 | 22 | // Overflow! |
1646 | 22 | return 0; |
1647 | 22 | } |
1648 | 3.42k | } |
1649 | 1.24k | |
1650 | 1.24k | // Integer found. |
1651 | 1.24k | *aErrorCode = NS_OK; |
1652 | 956 | |
1653 | 956 | if (negate) { |
1654 | 271 | result = -result; |
1655 | 271 | } |
1656 | 956 | |
1657 | 956 | return result.value(); |
1658 | 1.24k | } int ToIntegerCommon<char, int>(nsTSubstring<char> const&, nsresult*, unsigned int) Line | Count | Source | 1565 | 1.25k | { | 1566 | 1.25k | MOZ_ASSERT(aRadix == 10 || aRadix == 16); | 1567 | 1.25k | | 1568 | 1.25k | // Initial value, override if we find an integer. | 1569 | 1.25k | *aErrorCode = NS_ERROR_ILLEGAL_VALUE; | 1570 | 1.25k | | 1571 | 1.25k | // Begin by skipping over leading chars that shouldn't be part of the number. | 1572 | 1.25k | auto cp = aSrc.BeginReading(); | 1573 | 1.25k | auto endcp = aSrc.EndReading(); | 1574 | 1.25k | bool negate = false; | 1575 | 1.25k | bool done = false; | 1576 | 1.25k | | 1577 | 1.25k | // NB: For backwards compatibility I'm not going to change this logic but | 1578 | 1.25k | // it seems really odd. Previously there was logic to auto-detect the | 1579 | 1.25k | // radix if kAutoDetect was passed in. In practice this value was never | 1580 | 1.25k | // used, so it pretended to auto detect and skipped some preceding | 1581 | 1.25k | // letters (excluding valid hex digits) but never used the result. | 1582 | 1.25k | // | 1583 | 1.25k | // For example if you pass in "Get the number: 10", aRadix = 10 we'd | 1584 | 1.25k | // skip the 'G', and then fail to parse "et the number: 10". If aRadix = | 1585 | 1.25k | // 16 we'd skip the 'G', and parse just 'e' returning 14. | 1586 | 12.8k | while ((cp < endcp) && (!done)) { | 1587 | 11.5k | switch (*cp++) { | 1588 | 11.5k | // clang-format off | 1589 | 11.5k | case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': | 1590 | 1.24k | case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': | 1591 | 1.24k | case '0': case '1': case '2': case '3': case '4': | 1592 | 1.24k | case '5': case '6': case '7': case '8': case '9': | 1593 | 1.24k | done = true; | 1594 | 1.24k | break; | 1595 | 1.24k | // clang-format on | 1596 | 1.24k | case '-': | 1597 | 276 | negate = true; | 1598 | 276 | break; | 1599 | 10.0k | default: | 1600 | 10.0k | break; | 1601 | 11.5k | } | 1602 | 11.5k | } | 1603 | 1.25k | | 1604 | 1.25k | if (!done) { | 1605 | 12 | // No base 16 or base 10 digits were found. | 1606 | 12 | return 0; | 1607 | 12 | } | 1608 | 1.24k | | 1609 | 1.24k | // Step back. | 1610 | 1.24k | cp--; | 1611 | 1.24k | | 1612 | 1.24k | mozilla::CheckedInt<int_type> result; | 1613 | 1.24k | | 1614 | 1.24k | // Now iterate the numeric chars and build our result. | 1615 | 4.64k | while (cp < endcp) { | 1616 | 3.93k | auto theChar = *cp++; | 1617 | 3.93k | if (('0' <= theChar) && (theChar <= '9')) { | 1618 | 3.42k | result = (aRadix * result) + (theChar - '0'); | 1619 | 3.42k | } else if ((theChar >= 'A') && (theChar <= 'F')) { | 1620 | 0 | if (10 == aRadix) { | 1621 | 0 | // Invalid base 10 digit, error out. | 1622 | 0 | return 0; | 1623 | 0 | } else { | 1624 | 0 | result = (aRadix * result) + ((theChar - 'A') + 10); | 1625 | 0 | } | 1626 | 511 | } else if ((theChar >= 'a') && (theChar <= 'f')) { | 1627 | 267 | if (10 == aRadix) { | 1628 | 267 | // Invalid base 10 digit, error out. | 1629 | 267 | return 0; | 1630 | 267 | } else { | 1631 | 0 | result = (aRadix * result) + ((theChar - 'a') + 10); | 1632 | 0 | } | 1633 | 267 | } else if ((('X' == theChar) || ('x' == theChar)) && result == 0) { | 1634 | 0 | // For some reason we support a leading 'x' regardless of radix. For | 1635 | 0 | // example: "000000x500", aRadix = 10 would be parsed as 500 rather | 1636 | 0 | // than 0. | 1637 | 0 | continue; | 1638 | 244 | } else { | 1639 | 244 | // We've encountered a char that's not a legal number or sign and we can | 1640 | 244 | // terminate processing. | 1641 | 244 | break; | 1642 | 244 | } | 1643 | 3.42k | | 1644 | 3.42k | if (!result.isValid()) { | 1645 | 22 | // Overflow! | 1646 | 22 | return 0; | 1647 | 22 | } | 1648 | 3.42k | } | 1649 | 1.24k | | 1650 | 1.24k | // Integer found. | 1651 | 1.24k | *aErrorCode = NS_OK; | 1652 | 956 | | 1653 | 956 | if (negate) { | 1654 | 271 | result = -result; | 1655 | 271 | } | 1656 | 956 | | 1657 | 956 | return result.value(); | 1658 | 1.24k | } |
Unexecuted instantiation: long ToIntegerCommon<char, long>(nsTSubstring<char> const&, nsresult*, unsigned int) Unexecuted instantiation: int ToIntegerCommon<char16_t, int>(nsTSubstring<char16_t> const&, nsresult*, unsigned int) Unexecuted instantiation: long ToIntegerCommon<char16_t, long>(nsTSubstring<char16_t> const&, nsresult*, unsigned int) |
1659 | | |
1660 | | |
1661 | | template <typename T> |
1662 | | int32_t |
1663 | | nsTSubstring<T>::ToInteger(nsresult* aErrorCode, uint32_t aRadix) const |
1664 | 1.25k | { |
1665 | 1.25k | return ToIntegerCommon<T, int32_t>(*this, aErrorCode, aRadix); |
1666 | 1.25k | } nsTSubstring<char>::ToInteger(nsresult*, unsigned int) const Line | Count | Source | 1664 | 1.25k | { | 1665 | 1.25k | return ToIntegerCommon<T, int32_t>(*this, aErrorCode, aRadix); | 1666 | 1.25k | } |
Unexecuted instantiation: nsTSubstring<char16_t>::ToInteger(nsresult*, unsigned int) const |
1667 | | |
1668 | | |
1669 | | /** |
1670 | | * nsTSubstring::ToInteger64 |
1671 | | */ |
1672 | | template <typename T> |
1673 | | int64_t |
1674 | | nsTSubstring<T>::ToInteger64(nsresult* aErrorCode, uint32_t aRadix) const |
1675 | 0 | { |
1676 | 0 | return ToIntegerCommon<T, int64_t>(*this, aErrorCode, aRadix); |
1677 | 0 | } Unexecuted instantiation: nsTSubstring<char>::ToInteger64(nsresult*, unsigned int) const Unexecuted instantiation: nsTSubstring<char16_t>::ToInteger64(nsresult*, unsigned int) const |