Bug 1874684 - Part 4: Prefer const references instead of copying Instant values....
[gecko.git] / xpcom / string / nsTSubstring.h
blob0b4022823f4fbf8e578e2c17e983112f8d2c6c3b
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 // IWYU pragma: private, include "nsString.h"
8 #ifndef nsTSubstring_h
9 #define nsTSubstring_h
11 #include <iterator>
12 #include <type_traits>
14 #include "mozilla/Casting.h"
15 #include "mozilla/DebugOnly.h"
16 #include "mozilla/IntegerPrintfMacros.h"
17 #include "mozilla/UniquePtr.h"
18 #include "mozilla/Maybe.h"
19 #include "mozilla/MemoryReporting.h"
20 #include "mozilla/IntegerTypeTraits.h"
21 #include "mozilla/ResultExtensions.h"
22 #include "mozilla/Span.h"
23 #include "mozilla/Try.h"
24 #include "mozilla/Unused.h"
26 #include "nsTStringRepr.h"
28 #ifndef MOZILLA_INTERNAL_API
29 # error "Using XPCOM strings is limited to code linked into libxul."
30 #endif
32 // The max number of logically uninitialized code units to
33 // fill with a marker byte or to mark as unintialized for
34 // memory checking. (Limited to avoid quadratic behavior.)
35 const size_t kNsStringBufferMaxPoison = 16;
37 class nsStringBuffer;
38 template <typename T>
39 class nsTSubstringSplitter;
40 template <typename T>
41 class nsTString;
42 template <typename T>
43 class nsTSubstring;
45 namespace mozilla {
47 /**
48 * This handle represents permission to perform low-level writes
49 * the storage buffer of a string in a manner that's aware of the
50 * actual capacity of the storage buffer allocation and that's
51 * cache-friendly in the sense that the writing of zero terminator
52 * for C compatibility can happen in linear memory access order
53 * (i.e. the zero terminator write takes place after writing
54 * new content to the string as opposed to the zero terminator
55 * write happening first causing a non-linear memory write for
56 * cache purposes).
58 * If you requested a prefix to be preserved when starting
59 * or restarting the bulk write, the prefix is present at the
60 * start of the buffer exposed by this handle as Span or
61 * as a raw pointer, and it's your responsibility to start
62 * writing after after the preserved prefix (which you
63 * presumably wanted not to overwrite since you asked for
64 * it to be preserved).
66 * In a success case, you must call Finish() with the new
67 * length of the string. In failure cases, it's OK to return
68 * early from the function whose local variable this handle is.
69 * The destructor of this class takes care of putting the
70 * string in a valid and mostly harmless state in that case
71 * by setting the value of a non-empty string to a single
72 * REPLACEMENT CHARACTER or in the case of nsACString that's
73 * too short for a REPLACEMENT CHARACTER to fit, an ASCII
74 * SUBSTITUTE.
76 * You must not allow this handle to outlive the string you
77 * obtained it from.
79 * You must not access the string you obtained this handle
80 * from in any way other than through this handle until
81 * you call Finish() on the handle or the handle goes out
82 * of scope.
84 * Once you've called Finish(), you must not call any
85 * methods on this handle and must not use values previously
86 * obtained.
88 * Once you call RestartBulkWrite(), you must not use
89 * values previously obtained from this handle and must
90 * reobtain the new corresponding values.
92 template <typename T>
93 class BulkWriteHandle final {
94 friend class nsTSubstring<T>;
96 public:
97 typedef typename mozilla::detail::nsTStringRepr<T> base_string_type;
98 typedef typename base_string_type::size_type size_type;
101 * Pointer to the start of the writable buffer. Never nullptr.
103 * This pointer is valid until whichever of these happens first:
104 * 1) Finish() is called
105 * 2) RestartBulkWrite() is called
106 * 3) BulkWriteHandle goes out of scope
108 T* Elements() const {
109 MOZ_ASSERT(mString);
110 return mString->mData;
114 * How many code units can be written to the buffer.
115 * (Note: This is not the same as the string's Length().)
117 * This value is valid until whichever of these happens first:
118 * 1) Finish() is called
119 * 2) RestartBulkWrite() is called
120 * 3) BulkWriteHandle goes out of scope
122 size_type Length() const {
123 MOZ_ASSERT(mString);
124 return mCapacity;
128 * Pointer past the end of the buffer.
130 * This pointer is valid until whichever of these happens first:
131 * 1) Finish() is called
132 * 2) RestartBulkWrite() is called
133 * 3) BulkWriteHandle goes out of scope
135 T* End() const { return Elements() + Length(); }
138 * The writable buffer as Span.
140 * This Span is valid until whichever of these happens first:
141 * 1) Finish() is called
142 * 2) RestartBulkWrite() is called
143 * 3) BulkWriteHandle goes out of scope
145 auto AsSpan() const { return mozilla::Span<T>{Elements(), Length()}; }
148 * Autoconvert to the buffer as writable Span.
150 * This Span is valid until whichever of these happens first:
151 * 1) Finish() is called
152 * 2) RestartBulkWrite() is called
153 * 3) BulkWriteHandle goes out of scope
155 operator mozilla::Span<T>() const { return AsSpan(); }
158 * Restart the bulk write with a different capacity.
160 * This method invalidates previous return values
161 * of the other methods above.
163 * Can fail if out of memory leaving the buffer
164 * in the state before this call.
166 * @param aCapacity the new requested capacity
167 * @param aPrefixToPreserve the number of code units at
168 * the start of the string to
169 * copy over to the new buffer
170 * @param aAllowShrinking whether the string is
171 * allowed to attempt to
172 * allocate a smaller buffer
173 * for its content and copy
174 * the data over.
176 mozilla::Result<mozilla::Ok, nsresult> RestartBulkWrite(
177 size_type aCapacity, size_type aPrefixToPreserve, bool aAllowShrinking) {
178 MOZ_ASSERT(mString);
179 MOZ_TRY_VAR(mCapacity, mString->StartBulkWriteImpl(
180 aCapacity, aPrefixToPreserve, aAllowShrinking));
181 return mozilla::Ok();
185 * Indicate that the bulk write finished successfully.
187 * @param aLength the number of code units written;
188 * must not exceed Length()
189 * @param aAllowShrinking whether the string is
190 * allowed to attempt to
191 * allocate a smaller buffer
192 * for its content and copy
193 * the data over.
195 void Finish(size_type aLength, bool aAllowShrinking) {
196 MOZ_ASSERT(mString);
197 MOZ_ASSERT(aLength <= mCapacity);
198 if (!aLength) {
199 // Truncate is safe even when the string is in an invalid state
200 mString->Truncate();
201 mString = nullptr;
202 return;
204 if (aAllowShrinking) {
205 mozilla::Unused << mString->StartBulkWriteImpl(aLength, aLength, true);
207 mString->FinishBulkWriteImpl(aLength);
208 mString = nullptr;
211 BulkWriteHandle(BulkWriteHandle&& aOther)
212 : mString(aOther.Forget()), mCapacity(aOther.mCapacity) {}
214 ~BulkWriteHandle() {
215 if (!mString || !mCapacity) {
216 return;
218 // The old zero terminator may be gone by now, so we need
219 // to write a new one somewhere and make length match.
220 // We can use a length between 1 and self.capacity.
221 // The contents of the string can be partially uninitialized
222 // or partially initialized in a way that would be dangerous
223 // if parsed by some recipient. It's prudent to write something
224 // same as the contents of the string. U+FFFD is the safest
225 // placeholder, but when it doesn't fit, let's use ASCII
226 // substitute. Merely truncating the string to a zero-length
227 // string might be dangerous in some scenarios. See
228 // https://www.unicode.org/reports/tr36/#Substituting_for_Ill_Formed_Subsequences
229 // for closely related scenario.
230 auto ptr = Elements();
231 // Cast the pointer below to silence warnings
232 if (sizeof(T) == 1) {
233 unsigned char* charPtr = reinterpret_cast<unsigned char*>(ptr);
234 if (mCapacity >= 3) {
235 *charPtr++ = 0xEF;
236 *charPtr++ = 0xBF;
237 *charPtr++ = 0xBD;
238 mString->mLength = 3;
239 } else {
240 *charPtr++ = 0x1A;
241 mString->mLength = 1;
243 *charPtr = 0;
244 } else if (sizeof(T) == 2) {
245 char16_t* charPtr = reinterpret_cast<char16_t*>(ptr);
246 *charPtr++ = 0xFFFD;
247 *charPtr = 0;
248 mString->mLength = 1;
249 } else {
250 MOZ_ASSERT_UNREACHABLE("Only 8-bit and 16-bit code units supported.");
254 BulkWriteHandle() = delete;
255 BulkWriteHandle(const BulkWriteHandle&) = delete;
256 BulkWriteHandle& operator=(const BulkWriteHandle&) = delete;
258 private:
259 BulkWriteHandle(nsTSubstring<T>* aString, size_type aCapacity)
260 : mString(aString), mCapacity(aCapacity) {}
262 nsTSubstring<T>* Forget() {
263 auto string = mString;
264 mString = nullptr;
265 return string;
268 nsTSubstring<T>* mString; // nullptr upon finish
269 size_type mCapacity;
272 } // namespace mozilla
275 * nsTSubstring is an abstract string class. From an API perspective, this
276 * class is the root of the string class hierarchy. It represents a single
277 * contiguous array of characters, which may or may not be null-terminated.
278 * This type is not instantiated directly. A sub-class is instantiated
279 * instead. For example, see nsTString.
281 * NAMES:
282 * nsAString for wide characters
283 * nsACString for narrow characters
286 template <typename T>
287 class nsTSubstring : public mozilla::detail::nsTStringRepr<T> {
288 friend class mozilla::BulkWriteHandle<T>;
289 friend class nsStringBuffer;
291 public:
292 typedef nsTSubstring<T> self_type;
294 typedef nsTString<T> string_type;
296 typedef typename mozilla::detail::nsTStringRepr<T> base_string_type;
297 typedef typename base_string_type::substring_type substring_type;
299 typedef typename base_string_type::fallible_t fallible_t;
301 typedef typename base_string_type::char_type char_type;
302 typedef typename base_string_type::char_traits char_traits;
303 typedef
304 typename base_string_type::incompatible_char_type incompatible_char_type;
306 typedef typename base_string_type::substring_tuple_type substring_tuple_type;
308 typedef typename base_string_type::const_iterator const_iterator;
309 typedef typename base_string_type::iterator iterator;
311 typedef typename base_string_type::comparator_type comparator_type;
313 typedef typename base_string_type::const_char_iterator const_char_iterator;
315 typedef typename base_string_type::string_view string_view;
317 typedef typename base_string_type::index_type index_type;
318 typedef typename base_string_type::size_type size_type;
320 // These are only for internal use within the string classes:
321 typedef typename base_string_type::DataFlags DataFlags;
322 typedef typename base_string_type::ClassFlags ClassFlags;
323 typedef typename base_string_type::LengthStorage LengthStorage;
325 // this acts like a virtual destructor
326 ~nsTSubstring() { Finalize(); }
329 * writing iterators
331 * BeginWriting() makes the string mutable (if it isn't
332 * already) and returns (or writes into an outparam) a
333 * pointer that provides write access to the string's buffer.
335 * Note: Consider if BulkWrite() suits your use case better
336 * than BeginWriting() combined with SetLength().
338 * Note: Strings autoconvert into writable mozilla::Span,
339 * which may suit your use case better than calling
340 * BeginWriting() directly.
342 * When writing via the pointer obtained from BeginWriting(),
343 * you are allowed to write at most the number of code units
344 * indicated by Length() or, alternatively, write up to, but
345 * not including, the position indicated by EndWriting().
347 * In particular, calling SetCapacity() does not affect what
348 * the above paragraph says.
351 iterator BeginWriting() {
352 if (!EnsureMutable()) {
353 AllocFailed(base_string_type::mLength);
356 return base_string_type::mData;
359 iterator BeginWriting(const fallible_t&) {
360 return EnsureMutable() ? base_string_type::mData : iterator(0);
363 iterator EndWriting() {
364 if (!EnsureMutable()) {
365 AllocFailed(base_string_type::mLength);
368 return base_string_type::mData + base_string_type::mLength;
371 iterator EndWriting(const fallible_t&) {
372 return EnsureMutable()
373 ? (base_string_type::mData + base_string_type::mLength)
374 : iterator(0);
378 * Perform string to int conversion.
379 * @param aErrorCode will contain error if one occurs
380 * @param aRadix is the radix to use. Only 10 and 16 are supported.
381 * @return int rep of string value, and possible (out) error code
383 int32_t ToInteger(nsresult* aErrorCode, uint32_t aRadix = 10) const;
386 * Perform string to 64-bit int conversion.
387 * @param aErrorCode will contain error if one occurs
388 * @param aRadix is the radix to use. Only 10 and 16 are supported.
389 * @return 64-bit int rep of string value, and possible (out) error code
391 int64_t ToInteger64(nsresult* aErrorCode, uint32_t aRadix = 10) const;
394 * assignment
397 void NS_FASTCALL Assign(char_type aChar);
398 [[nodiscard]] bool NS_FASTCALL Assign(char_type aChar, const fallible_t&);
400 void NS_FASTCALL Assign(const char_type* aData,
401 size_type aLength = size_type(-1));
402 [[nodiscard]] bool NS_FASTCALL Assign(const char_type* aData,
403 const fallible_t&);
404 [[nodiscard]] bool NS_FASTCALL Assign(const char_type* aData,
405 size_type aLength, const fallible_t&);
407 void NS_FASTCALL Assign(const self_type&);
408 [[nodiscard]] bool NS_FASTCALL Assign(const self_type&, const fallible_t&);
410 void NS_FASTCALL Assign(self_type&&);
411 [[nodiscard]] bool NS_FASTCALL Assign(self_type&&, const fallible_t&);
413 void NS_FASTCALL Assign(const substring_tuple_type&);
414 [[nodiscard]] bool NS_FASTCALL Assign(const substring_tuple_type&,
415 const fallible_t&);
417 #if defined(MOZ_USE_CHAR16_WRAPPER)
418 template <typename Q = T, typename EnableIfChar16 = mozilla::Char16OnlyT<Q>>
419 void Assign(char16ptr_t aData) {
420 Assign(static_cast<const char16_t*>(aData));
423 template <typename Q = T, typename EnableIfChar16 = mozilla::Char16OnlyT<Q>>
424 void Assign(char16ptr_t aData, size_type aLength) {
425 Assign(static_cast<const char16_t*>(aData), aLength);
428 template <typename Q = T, typename EnableIfChar16 = mozilla::Char16OnlyT<Q>>
429 [[nodiscard]] bool Assign(char16ptr_t aData, size_type aLength,
430 const fallible_t& aFallible) {
431 return Assign(static_cast<const char16_t*>(aData), aLength, aFallible);
433 #endif
435 void NS_FASTCALL AssignASCII(const char* aData, size_type aLength);
436 [[nodiscard]] bool NS_FASTCALL AssignASCII(const char* aData,
437 size_type aLength,
438 const fallible_t&);
440 void NS_FASTCALL AssignASCII(const char* aData) {
441 AssignASCII(aData, strlen(aData));
443 [[nodiscard]] bool NS_FASTCALL AssignASCII(const char* aData,
444 const fallible_t& aFallible) {
445 return AssignASCII(aData, strlen(aData), aFallible);
448 // AssignLiteral must ONLY be called with an actual literal string, or
449 // a character array *constant* of static storage duration declared
450 // without an explicit size and with an initializer that is a string
451 // literal or is otherwise null-terminated.
452 // Use Assign or AssignASCII for other character array variables.
454 // This method does not need a fallible version, because it uses the
455 // POD buffer of the literal as the string's buffer without allocating.
456 // The literal does not need to be ASCII. If this a 16-bit string, this
457 // method takes a u"" literal. (The overload on 16-bit strings that takes
458 // a "" literal takes only ASCII.)
459 template <int N>
460 void AssignLiteral(const char_type (&aStr)[N]) {
461 AssignLiteral(aStr, N - 1);
464 // AssignLiteral must ONLY be called with an actual literal string, or
465 // a char array *constant* declared without an explicit size and with an
466 // initializer that is a string literal or is otherwise null-terminated.
467 // Use AssignASCII for other char array variables.
469 // This method takes an 8-bit (ASCII-only!) string that is expanded
470 // into a 16-bit string at run time causing a run-time allocation.
471 // To avoid the run-time allocation (at the cost of the literal
472 // taking twice the size in the binary), use the above overload that
473 // takes a u"" string instead. Using the overload that takes a u""
474 // literal is generally preferred when working with 16-bit strings.
476 // There is not a fallible version of this method because it only really
477 // applies to small allocations that we wouldn't want to check anyway.
478 template <int N, typename Q = T,
479 typename EnableIfChar16 = typename mozilla::Char16OnlyT<Q>>
480 void AssignLiteral(const incompatible_char_type (&aStr)[N]) {
481 AssignASCII(aStr, N - 1);
484 self_type& operator=(char_type aChar) {
485 Assign(aChar);
486 return *this;
488 self_type& operator=(const char_type* aData) {
489 Assign(aData);
490 return *this;
492 #if defined(MOZ_USE_CHAR16_WRAPPER)
493 template <typename Q = T, typename EnableIfChar16 = mozilla::Char16OnlyT<Q>>
494 self_type& operator=(char16ptr_t aData) {
495 Assign(aData);
496 return *this;
498 #endif
499 self_type& operator=(const self_type& aStr) {
500 Assign(aStr);
501 return *this;
503 self_type& operator=(self_type&& aStr) {
504 Assign(std::move(aStr));
505 return *this;
507 self_type& operator=(const substring_tuple_type& aTuple) {
508 Assign(aTuple);
509 return *this;
512 // Adopt a heap-allocated char sequence for this string; is Voided if aData
513 // is null. Useful for e.g. converting an strdup'd C string into an
514 // nsCString. See also getter_Copies(), which is a useful wrapper.
515 void NS_FASTCALL Adopt(char_type* aData, size_type aLength = size_type(-1));
518 * buffer manipulation
521 void NS_FASTCALL Replace(index_type aCutStart, size_type aCutLength,
522 char_type aChar);
523 [[nodiscard]] bool NS_FASTCALL Replace(index_type aCutStart,
524 size_type aCutLength, char_type aChar,
525 const fallible_t&);
526 void NS_FASTCALL Replace(index_type aCutStart, size_type aCutLength,
527 const char_type* aData,
528 size_type aLength = size_type(-1));
529 [[nodiscard]] bool NS_FASTCALL Replace(index_type aCutStart,
530 size_type aCutLength,
531 const char_type* aData,
532 size_type aLength, const fallible_t&);
533 void Replace(index_type aCutStart, size_type aCutLength,
534 const self_type& aStr) {
535 Replace(aCutStart, aCutLength, aStr.Data(), aStr.Length());
537 [[nodiscard]] bool Replace(index_type aCutStart, size_type aCutLength,
538 const self_type& aStr,
539 const fallible_t& aFallible) {
540 return Replace(aCutStart, aCutLength, aStr.Data(), aStr.Length(),
541 aFallible);
543 void NS_FASTCALL Replace(index_type aCutStart, size_type aCutLength,
544 const substring_tuple_type& aTuple);
546 // ReplaceLiteral must ONLY be called with an actual literal string, or
547 // a character array *constant* of static storage duration declared
548 // without an explicit size and with an initializer that is a string
549 // literal or is otherwise null-terminated.
550 // Use Replace for other character array variables.
551 template <int N>
552 void ReplaceLiteral(index_type aCutStart, size_type aCutLength,
553 const char_type (&aStr)[N]) {
554 ReplaceLiteral(aCutStart, aCutLength, aStr, N - 1);
558 * |Left|, |Mid|, and |Right| are annoying signatures that seem better almost
559 * any _other_ way than they are now. Consider these alternatives
561 * // ...a member function that returns a |Substring|
562 * aWritable = aReadable.Left(17);
563 * // ...a global function that returns a |Substring|
564 * aWritable = Left(aReadable, 17);
565 * // ...a global function that does the assignment
566 * Left(aReadable, 17, aWritable);
568 * as opposed to the current signature
570 * // ...a member function that does the assignment
571 * aReadable.Left(aWritable, 17);
573 * or maybe just stamping them out in favor of |Substring|, they are just
574 * duplicate functionality
576 * aWritable = Substring(aReadable, 0, 17);
578 size_type Mid(self_type& aResult, index_type aStartPos,
579 size_type aCount) const;
581 size_type Left(self_type& aResult, size_type aCount) const {
582 return Mid(aResult, 0, aCount);
585 size_type Right(self_type& aResult, size_type aCount) const {
586 aCount = XPCOM_MIN(this->Length(), aCount);
587 return Mid(aResult, this->mLength - aCount, aCount);
591 * This method strips whitespace throughout the string.
593 void StripWhitespace();
594 bool StripWhitespace(const fallible_t&);
597 * This method is used to remove all occurrences of aChar from this
598 * string.
600 * @param aChar -- char to be stripped
602 void StripChar(char_type aChar);
605 * This method is used to remove all occurrences of aChars from this
606 * string.
608 * @param aChars -- chars to be stripped
610 void StripChars(const char_type* aChars);
613 * This method is used to remove all occurrences of some characters this
614 * from this string. The characters removed have the corresponding
615 * entries in the bool array set to true; we retain all characters
616 * with code beyond 127.
617 * THE CALLER IS RESPONSIBLE for making sure the complete boolean
618 * array, 128 entries, is properly initialized.
620 * See also: ASCIIMask class.
622 * @param aToStrip -- Array where each entry is true if the
623 * corresponding ASCII character is to be stripped. All
624 * characters beyond code 127 are retained. Note that this
625 * parameter is of ASCIIMaskArray type, but we expand the typedef
626 * to avoid having to include nsASCIIMask.h in this include file
627 * as it brings other includes.
629 void StripTaggedASCII(const std::array<bool, 128>& aToStrip);
632 * A shortcut to strip \r and \n.
634 void StripCRLF();
637 * swaps occurence of 1 string for another
639 void ReplaceChar(char_type aOldChar, char_type aNewChar);
640 void ReplaceChar(const string_view& aSet, char_type aNewChar);
643 * Replace all occurrences of aTarget with aNewValue.
644 * The complexity of this function is O(n+m), n being the length of the string
645 * and m being the length of aNewValue.
647 void ReplaceSubstring(const self_type& aTarget, const self_type& aNewValue);
648 void ReplaceSubstring(const char_type* aTarget, const char_type* aNewValue);
649 [[nodiscard]] bool ReplaceSubstring(const self_type& aTarget,
650 const self_type& aNewValue,
651 const fallible_t&);
652 [[nodiscard]] bool ReplaceSubstring(const char_type* aTarget,
653 const char_type* aNewValue,
654 const fallible_t&);
657 * This method trims characters found in aSet from either end of the
658 * underlying string.
660 * @param aSet -- contains chars to be trimmed from both ends
661 * @param aTrimLeading
662 * @param aTrimTrailing
663 * @param aIgnoreQuotes -- if true, causes surrounding quotes to be ignored
664 * @return this
666 void Trim(const std::string_view& aSet, bool aTrimLeading = true,
667 bool aTrimTrailing = true, bool aIgnoreQuotes = false);
670 * This method strips whitespace from string.
671 * You can control whether whitespace is yanked from start and end of
672 * string as well.
674 * @param aTrimLeading controls stripping of leading ws
675 * @param aTrimTrailing controls stripping of trailing ws
677 void CompressWhitespace(bool aTrimLeading = true, bool aTrimTrailing = true);
679 void Append(char_type aChar);
681 [[nodiscard]] bool Append(char_type aChar, const fallible_t& aFallible);
683 void Append(const char_type* aData, size_type aLength = size_type(-1));
685 [[nodiscard]] bool Append(const char_type* aData, size_type aLength,
686 const fallible_t& aFallible);
688 #if defined(MOZ_USE_CHAR16_WRAPPER)
689 template <typename Q = T, typename EnableIfChar16 = mozilla::Char16OnlyT<Q>>
690 void Append(char16ptr_t aData, size_type aLength = size_type(-1)) {
691 Append(static_cast<const char16_t*>(aData), aLength);
693 #endif
695 void Append(const self_type& aStr);
697 [[nodiscard]] bool Append(const self_type& aStr, const fallible_t& aFallible);
699 void Append(const substring_tuple_type& aTuple);
701 [[nodiscard]] bool Append(const substring_tuple_type& aTuple,
702 const fallible_t& aFallible);
704 void AppendASCII(const char* aData, size_type aLength = size_type(-1));
706 [[nodiscard]] bool AppendASCII(const char* aData,
707 const fallible_t& aFallible);
709 [[nodiscard]] bool AppendASCII(const char* aData, size_type aLength,
710 const fallible_t& aFallible);
712 // Appends a literal string ("" literal in the 8-bit case and u"" literal
713 // in the 16-bit case) to the string.
715 // AppendLiteral must ONLY be called with an actual literal string, or
716 // a character array *constant* of static storage duration declared
717 // without an explicit size and with an initializer that is a string
718 // literal or is otherwise null-terminated.
719 // Use Append or AppendASCII for other character array variables.
720 template <int N>
721 void AppendLiteral(const char_type (&aStr)[N]) {
722 // The case where base_string_type::mLength is zero is intentionally
723 // left unoptimized (could be optimized as call to AssignLiteral),
724 // because it's rare/nonexistent. If you add that optimization,
725 // please be sure to also check that
726 // !(base_string_type::mDataFlags & DataFlags::REFCOUNTED)
727 // to avoid undoing the effects of SetCapacity().
728 Append(aStr, N - 1);
731 template <int N>
732 void AppendLiteral(const char_type (&aStr)[N], const fallible_t& aFallible) {
733 // The case where base_string_type::mLength is zero is intentionally
734 // left unoptimized (could be optimized as call to AssignLiteral),
735 // because it's rare/nonexistent. If you add that optimization,
736 // please be sure to also check that
737 // !(base_string_type::mDataFlags & DataFlags::REFCOUNTED)
738 // to avoid undoing the effects of SetCapacity().
739 return Append(aStr, N - 1, aFallible);
742 // Only enable for T = char16_t
744 // Appends an 8-bit literal string ("" literal) to a 16-bit string by
745 // expanding it. The literal must only contain ASCII.
747 // Using u"" literals with 16-bit strings is generally preferred.
748 template <int N, typename Q = T,
749 typename EnableIfChar16 = mozilla::Char16OnlyT<Q>>
750 void AppendLiteral(const incompatible_char_type (&aStr)[N]) {
751 AppendASCII(aStr, N - 1);
754 // Only enable for T = char16_t
755 template <int N, typename Q = T,
756 typename EnableIfChar16 = mozilla::Char16OnlyT<Q>>
757 [[nodiscard]] bool AppendLiteral(const incompatible_char_type (&aStr)[N],
758 const fallible_t& aFallible) {
759 return AppendASCII(aStr, N - 1, aFallible);
763 * Append a formatted string to the current string. Uses the
764 * standard printf format codes. This uses NSPR formatting, which will be
765 * locale-aware for floating-point values. You probably don't want to use
766 * this with floating-point values as a result.
768 void AppendPrintf(const char* aFormat, ...) MOZ_FORMAT_PRINTF(2, 3);
769 void AppendVprintf(const char* aFormat, va_list aAp) MOZ_FORMAT_PRINTF(2, 0);
770 void AppendInt(int32_t aInteger) { AppendIntDec(aInteger); }
771 void AppendInt(int32_t aInteger, int aRadix) {
772 if (aRadix == 10) {
773 AppendIntDec(aInteger);
774 } else if (aRadix == 8) {
775 AppendIntOct(static_cast<uint32_t>(aInteger));
776 } else {
777 AppendIntHex(static_cast<uint32_t>(aInteger));
780 void AppendInt(uint32_t aInteger) { AppendIntDec(aInteger); }
781 void AppendInt(uint32_t aInteger, int aRadix) {
782 if (aRadix == 10) {
783 AppendIntDec(aInteger);
784 } else if (aRadix == 8) {
785 AppendIntOct(aInteger);
786 } else {
787 AppendIntHex(aInteger);
790 void AppendInt(int64_t aInteger) { AppendIntDec(aInteger); }
791 void AppendInt(int64_t aInteger, int aRadix) {
792 if (aRadix == 10) {
793 AppendIntDec(aInteger);
794 } else if (aRadix == 8) {
795 AppendIntOct(static_cast<uint64_t>(aInteger));
796 } else {
797 AppendIntHex(static_cast<uint64_t>(aInteger));
800 void AppendInt(uint64_t aInteger) { AppendIntDec(aInteger); }
801 void AppendInt(uint64_t aInteger, int aRadix) {
802 if (aRadix == 10) {
803 AppendIntDec(aInteger);
804 } else if (aRadix == 8) {
805 AppendIntOct(aInteger);
806 } else {
807 AppendIntHex(aInteger);
811 private:
812 void AppendIntDec(int32_t);
813 void AppendIntDec(uint32_t);
814 void AppendIntOct(uint32_t);
815 void AppendIntHex(uint32_t);
816 void AppendIntDec(int64_t);
817 void AppendIntDec(uint64_t);
818 void AppendIntOct(uint64_t);
819 void AppendIntHex(uint64_t);
821 public:
823 * Append the given float to this string
825 void NS_FASTCALL AppendFloat(float aFloat);
826 void NS_FASTCALL AppendFloat(double aFloat);
828 self_type& operator+=(char_type aChar) {
829 Append(aChar);
830 return *this;
832 self_type& operator+=(const char_type* aData) {
833 Append(aData);
834 return *this;
836 #if defined(MOZ_USE_CHAR16_WRAPPER)
837 template <typename Q = T, typename EnableIfChar16 = mozilla::Char16OnlyT<Q>>
838 self_type& operator+=(char16ptr_t aData) {
839 Append(aData);
840 return *this;
842 #endif
843 self_type& operator+=(const self_type& aStr) {
844 Append(aStr);
845 return *this;
847 self_type& operator+=(const substring_tuple_type& aTuple) {
848 Append(aTuple);
849 return *this;
852 void Insert(char_type aChar, index_type aPos) { Replace(aPos, 0, aChar); }
853 void Insert(const char_type* aData, index_type aPos,
854 size_type aLength = size_type(-1)) {
855 Replace(aPos, 0, aData, aLength);
857 #if defined(MOZ_USE_CHAR16_WRAPPER)
858 template <typename Q = T, typename EnableIfChar16 = mozilla::Char16OnlyT<Q>>
859 void Insert(char16ptr_t aData, index_type aPos,
860 size_type aLength = size_type(-1)) {
861 Insert(static_cast<const char16_t*>(aData), aPos, aLength);
863 #endif
864 void Insert(const self_type& aStr, index_type aPos) {
865 Replace(aPos, 0, aStr);
867 void Insert(const substring_tuple_type& aTuple, index_type aPos) {
868 Replace(aPos, 0, aTuple);
871 // InsertLiteral must ONLY be called with an actual literal string, or
872 // a character array *constant* of static storage duration declared
873 // without an explicit size and with an initializer that is a string
874 // literal or is otherwise null-terminated.
875 // Use Insert for other character array variables.
876 template <int N>
877 void InsertLiteral(const char_type (&aStr)[N], index_type aPos) {
878 ReplaceLiteral(aPos, 0, aStr, N - 1);
881 void Cut(index_type aCutStart, size_type aCutLength) {
882 Replace(aCutStart, aCutLength, char_traits::sEmptyBuffer, 0);
885 nsTSubstringSplitter<T> Split(const char_type aChar) const;
888 * buffer sizing
892 * Attempts to set the capacity to the given size in number of
893 * code units without affecting the length of the string in
894 * order to avoid reallocation during a subsequent sequence of
895 * appends.
897 * This method is appropriate to use before a sequence of multiple
898 * operations from the following list (without operations that are
899 * not on the list between the SetCapacity() call and operations
900 * from the list):
902 * Append()
903 * AppendASCII()
904 * AppendLiteral() (except if the string is empty: bug 1487606)
905 * AppendPrintf()
906 * AppendInt()
907 * AppendFloat()
908 * LossyAppendUTF16toASCII()
909 * AppendASCIItoUTF16()
911 * DO NOT call SetCapacity() if the subsequent operations on the
912 * string do not meet the criteria above. Operations that undo
913 * the benefits of SetCapacity() include but are not limited to:
915 * SetLength()
916 * Truncate()
917 * Assign()
918 * AssignLiteral()
919 * Adopt()
920 * CopyASCIItoUTF16()
921 * LossyCopyUTF16toASCII()
922 * AppendUTF16toUTF8()
923 * AppendUTF8toUTF16()
924 * CopyUTF16toUTF8()
925 * CopyUTF8toUTF16()
927 * If your string is an nsAuto[C]String and you are calling
928 * SetCapacity() with a constant N, please instead declare the
929 * string as nsAuto[C]StringN<N+1> without calling SetCapacity().
931 * There is no need to include room for the null terminator: it is
932 * the job of the string class.
934 * Note: Calling SetCapacity() does not give you permission to
935 * use the pointer obtained from BeginWriting() to write
936 * past the current length (as returned by Length()) of the
937 * string. Please use either BulkWrite() or SetLength()
938 * instead.
940 * Note: SetCapacity() won't make the string shorter if
941 * called with an argument smaller than the length of the
942 * string.
944 * Note: You must not use previously obtained iterators
945 * or spans after calling SetCapacity().
947 void NS_FASTCALL SetCapacity(size_type aNewCapacity);
948 [[nodiscard]] bool NS_FASTCALL SetCapacity(size_type aNewCapacity,
949 const fallible_t&);
952 * Changes the logical length of the string, potentially
953 * allocating a differently-sized buffer for the string.
955 * When making the string shorter, this method never
956 * reports allocation failure.
958 * Exposes uninitialized memory if the string got longer.
960 * If called with the argument 0, releases the
961 * heap-allocated buffer, if any. (But the no-argument
962 * overload of Truncate() is a more idiomatic and efficient
963 * option than SetLength(0).)
965 * Note: You must not use previously obtained iterators
966 * or spans after calling SetLength().
968 void NS_FASTCALL SetLength(size_type aNewLength);
969 [[nodiscard]] bool NS_FASTCALL SetLength(size_type aNewLength,
970 const fallible_t&);
973 * Like SetLength() but asserts in that the string
974 * doesn't become longer. Never fails, so doesn't need a
975 * fallible variant.
977 * Note: You must not use previously obtained iterators
978 * or spans after calling Truncate().
980 void Truncate(size_type aNewLength) {
981 MOZ_RELEASE_ASSERT(aNewLength <= base_string_type::mLength,
982 "Truncate cannot make string longer");
983 mozilla::DebugOnly<bool> success = SetLength(aNewLength, mozilla::fallible);
984 MOZ_ASSERT(success);
988 * A more efficient overload for Truncate(0). Releases the
989 * heap-allocated buffer if any.
991 void Truncate();
994 * buffer access
998 * Get a const pointer to the string's internal buffer. The caller
999 * MUST NOT modify the characters at the returned address.
1001 * @returns The length of the buffer in characters.
1003 inline size_type GetData(const char_type** aData) const {
1004 *aData = base_string_type::mData;
1005 return base_string_type::mLength;
1009 * Get a pointer to the string's internal buffer, optionally resizing
1010 * the buffer first. If size_type(-1) is passed for newLen, then the
1011 * current length of the string is used. The caller MAY modify the
1012 * characters at the returned address (up to but not exceeding the
1013 * length of the string).
1015 * @returns The length of the buffer in characters or 0 if unable to
1016 * satisfy the request due to low-memory conditions.
1018 size_type GetMutableData(char_type** aData,
1019 size_type aNewLen = size_type(-1)) {
1020 if (!EnsureMutable(aNewLen)) {
1021 AllocFailed(aNewLen == size_type(-1) ? base_string_type::Length()
1022 : aNewLen);
1025 *aData = base_string_type::mData;
1026 return base_string_type::Length();
1029 size_type GetMutableData(char_type** aData, size_type aNewLen,
1030 const fallible_t&) {
1031 if (!EnsureMutable(aNewLen)) {
1032 *aData = nullptr;
1033 return 0;
1036 *aData = base_string_type::mData;
1037 return base_string_type::mLength;
1040 #if defined(MOZ_USE_CHAR16_WRAPPER)
1041 template <typename Q = T, typename EnableIfChar16 = mozilla::Char16OnlyT<Q>>
1042 size_type GetMutableData(wchar_t** aData, size_type aNewLen = size_type(-1)) {
1043 return GetMutableData(reinterpret_cast<char16_t**>(aData), aNewLen);
1046 template <typename Q = T, typename EnableIfChar16 = mozilla::Char16OnlyT<Q>>
1047 size_type GetMutableData(wchar_t** aData, size_type aNewLen,
1048 const fallible_t& aFallible) {
1049 return GetMutableData(reinterpret_cast<char16_t**>(aData), aNewLen,
1050 aFallible);
1052 #endif
1054 mozilla::Span<char_type> GetMutableData(size_type aNewLen = size_type(-1)) {
1055 if (!EnsureMutable(aNewLen)) {
1056 AllocFailed(aNewLen == size_type(-1) ? base_string_type::Length()
1057 : aNewLen);
1060 return mozilla::Span{base_string_type::mData, base_string_type::Length()};
1063 mozilla::Maybe<mozilla::Span<char_type>> GetMutableData(size_type aNewLen,
1064 const fallible_t&) {
1065 if (!EnsureMutable(aNewLen)) {
1066 return mozilla::Nothing();
1068 return Some(
1069 mozilla::Span{base_string_type::mData, base_string_type::Length()});
1073 * Span integration
1076 operator mozilla::Span<const char_type>() const {
1077 return mozilla::Span{base_string_type::BeginReading(),
1078 base_string_type::Length()};
1081 void Append(mozilla::Span<const char_type> aSpan) {
1082 Append(aSpan.Elements(), aSpan.Length());
1085 [[nodiscard]] bool Append(mozilla::Span<const char_type> aSpan,
1086 const fallible_t& aFallible) {
1087 return Append(aSpan.Elements(), aSpan.Length(), aFallible);
1090 void NS_FASTCALL AssignASCII(mozilla::Span<const char> aData) {
1091 AssignASCII(aData.Elements(), aData.Length());
1093 [[nodiscard]] bool NS_FASTCALL AssignASCII(mozilla::Span<const char> aData,
1094 const fallible_t& aFallible) {
1095 return AssignASCII(aData.Elements(), aData.Length(), aFallible);
1098 void AppendASCII(mozilla::Span<const char> aData) {
1099 AppendASCII(aData.Elements(), aData.Length());
1102 template <typename Q = T, typename EnableIfChar = mozilla::CharOnlyT<Q>>
1103 operator mozilla::Span<const uint8_t>() const {
1104 return mozilla::Span{
1105 reinterpret_cast<const uint8_t*>(base_string_type::BeginReading()),
1106 base_string_type::Length()};
1109 template <typename Q = T, typename EnableIfChar = mozilla::CharOnlyT<Q>>
1110 void Append(mozilla::Span<const uint8_t> aSpan) {
1111 Append(reinterpret_cast<const char*>(aSpan.Elements()), aSpan.Length());
1114 template <typename Q = T, typename EnableIfChar = mozilla::CharOnlyT<Q>>
1115 [[nodiscard]] bool Append(mozilla::Span<const uint8_t> aSpan,
1116 const fallible_t& aFallible) {
1117 return Append(reinterpret_cast<const char*>(aSpan.Elements()),
1118 aSpan.Length(), aFallible);
1121 void Insert(mozilla::Span<const char_type> aSpan, index_type aPos) {
1122 Insert(aSpan.Elements(), aPos, aSpan.Length());
1126 * string data is never null, but can be marked void. if true, the
1127 * string will be truncated. @see nsTSubstring::IsVoid
1130 void NS_FASTCALL SetIsVoid(bool);
1133 * If the string uses a shared buffer, this method
1134 * clears the pointer without releasing the buffer.
1136 void ForgetSharedBuffer() {
1137 if (base_string_type::mDataFlags & DataFlags::REFCOUNTED) {
1138 SetToEmptyBuffer();
1142 protected:
1143 void AssertValid() {
1144 MOZ_DIAGNOSTIC_ASSERT(!(this->mClassFlags & ClassFlags::INVALID_MASK));
1145 MOZ_DIAGNOSTIC_ASSERT(!(this->mDataFlags & DataFlags::INVALID_MASK));
1146 MOZ_ASSERT(!(this->mClassFlags & ClassFlags::NULL_TERMINATED) ||
1147 (this->mDataFlags & DataFlags::TERMINATED),
1148 "String classes whose static type guarantees a null-terminated "
1149 "buffer must not be assigned a non-null-terminated buffer.");
1152 public:
1154 * this is public to support automatic conversion of tuple to string
1155 * base type, which helps avoid converting to nsTAString.
1157 MOZ_IMPLICIT nsTSubstring(const substring_tuple_type& aTuple)
1158 : base_string_type(nullptr, 0, DataFlags(0), ClassFlags(0)) {
1159 AssertValid();
1160 Assign(aTuple);
1163 size_t SizeOfExcludingThisIfUnshared(
1164 mozilla::MallocSizeOf aMallocSizeOf) const;
1165 size_t SizeOfIncludingThisIfUnshared(
1166 mozilla::MallocSizeOf aMallocSizeOf) const;
1169 * WARNING: Only use these functions if you really know what you are
1170 * doing, because they can easily lead to double-counting strings. If
1171 * you do use them, please explain clearly in a comment why it's safe
1172 * and won't lead to double-counting.
1174 size_t SizeOfExcludingThisEvenIfShared(
1175 mozilla::MallocSizeOf aMallocSizeOf) const;
1176 size_t SizeOfIncludingThisEvenIfShared(
1177 mozilla::MallocSizeOf aMallocSizeOf) const;
1179 template <class N>
1180 void NS_ABORT_OOM(T) {
1181 struct never {}; // a compiler-friendly way to do static_assert(false)
1182 static_assert(
1183 std::is_same_v<N, never>,
1184 "In string classes, use AllocFailed to account for sizeof(char_type). "
1185 "Use the global ::NS_ABORT_OOM if you really have a count of bytes.");
1188 MOZ_ALWAYS_INLINE void AllocFailed(size_t aLength) {
1189 ::NS_ABORT_OOM(aLength * sizeof(char_type));
1192 protected:
1193 // default initialization
1194 nsTSubstring()
1195 : base_string_type(char_traits::sEmptyBuffer, 0, DataFlags::TERMINATED,
1196 ClassFlags(0)) {
1197 AssertValid();
1200 // copy-constructor, constructs as dependent on given object
1201 // (NOTE: this is for internal use only)
1202 nsTSubstring(const self_type& aStr)
1203 : base_string_type(aStr.base_string_type::mData,
1204 aStr.base_string_type::mLength,
1205 aStr.base_string_type::mDataFlags &
1206 (DataFlags::TERMINATED | DataFlags::VOIDED),
1207 ClassFlags(0)) {
1208 AssertValid();
1211 // initialization with ClassFlags
1212 explicit nsTSubstring(ClassFlags aClassFlags)
1213 : base_string_type(char_traits::sEmptyBuffer, 0, DataFlags::TERMINATED,
1214 aClassFlags) {
1215 AssertValid();
1219 * allows for direct initialization of a nsTSubstring object.
1221 nsTSubstring(char_type* aData, size_type aLength, DataFlags aDataFlags,
1222 ClassFlags aClassFlags)
1223 #if defined(NS_BUILD_REFCNT_LOGGING)
1224 # define XPCOM_STRING_CONSTRUCTOR_OUT_OF_LINE
1226 #else
1227 # undef XPCOM_STRING_CONSTRUCTOR_OUT_OF_LINE
1228 : base_string_type(aData, aLength, aDataFlags, aClassFlags) {
1229 AssertValid();
1231 #endif /* NS_BUILD_REFCNT_LOGGING */
1233 void SetToEmptyBuffer() {
1234 base_string_type::mData = char_traits::sEmptyBuffer;
1235 base_string_type::mLength = 0;
1236 base_string_type::mDataFlags = DataFlags::TERMINATED;
1237 AssertValid();
1240 void SetData(char_type* aData, LengthStorage aLength, DataFlags aDataFlags) {
1241 base_string_type::mData = aData;
1242 base_string_type::mLength = aLength;
1243 base_string_type::mDataFlags = aDataFlags;
1244 AssertValid();
1248 * this function releases mData and does not change the value of
1249 * any of its member variables. in other words, this function acts
1250 * like a destructor.
1252 void NS_FASTCALL Finalize();
1254 public:
1256 * Starts a low-level write transaction to the string.
1258 * Prepares the string for mutation such that the capacity
1259 * of the string is at least aCapacity. The returned handle
1260 * exposes the actual, potentially larger, capacity.
1262 * If meeting the capacity or mutability requirement requires
1263 * reallocation, aPrefixToPreserve code units are copied from the
1264 * start of the old buffer to the start of the new buffer.
1265 * aPrefixToPreserve must not be greater than the string's current
1266 * length or greater than aCapacity.
1268 * aAllowShrinking indicates whether an allocation may be
1269 * performed when the string is already mutable and the requested
1270 * capacity is smaller than the current capacity.
1272 * If this method returns successfully, you must not access
1273 * the string except through the returned BulkWriteHandle
1274 * until either the BulkWriteHandle goes out of scope or
1275 * you call Finish() on the BulkWriteHandle.
1277 * Compared to SetLength() and BeginWriting(), this more
1278 * complex API accomplishes two things:
1279 * 1) It exposes the actual capacity which may be larger
1280 * than the requested capacity, which is useful in some
1281 * multi-step write operations that don't allocate for
1282 * the worst case up front.
1283 * 2) It writes the zero terminator after the string
1284 * content has been written, which results in a
1285 * cache-friendly linear write pattern.
1287 mozilla::Result<mozilla::BulkWriteHandle<T>, nsresult> NS_FASTCALL BulkWrite(
1288 size_type aCapacity, size_type aPrefixToPreserve, bool aAllowShrinking);
1291 * THIS IS NOT REALLY A PUBLIC METHOD! DO NOT CALL FROM OUTSIDE
1292 * THE STRING IMPLEMENTATION. (It's public only because friend
1293 * declarations don't allow extern or static and this needs to
1294 * be called from Rust FFI glue.)
1296 * Prepares mData to be mutated such that the capacity of the string
1297 * (not counting the zero-terminator) is at least aCapacity.
1298 * Returns the actual capacity, which may be larger than what was
1299 * requested or Err(NS_ERROR_OUT_OF_MEMORY) on allocation failure.
1301 * mLength is ignored by this method. If the buffer is reallocated,
1302 * aUnitsToPreserve specifies how many code units to copy over to
1303 * the new buffer. The old buffer is freed if applicable.
1305 * Unless the return value is Err(NS_ERROR_OUT_OF_MEMORY) to signal
1306 * failure or 0 to signal that the string has been set to
1307 * the special empty state, this method leaves the string in an
1308 * invalid state! The caller is responsible for calling
1309 * FinishBulkWrite() (or in Rust calling
1310 * nsA[C]StringBulkWriteHandle::finish()), which put the string
1311 * into a valid state by setting mLength and zero-terminating.
1312 * This method sets the flag to claim that the string is
1313 * zero-terminated before it actually is.
1315 * Once this method has been called and before FinishBulkWrite()
1316 * has been called, only accessing mData or calling this method
1317 * again are valid operations. Do not call any other methods or
1318 * access other fields between calling this method and
1319 * FinishBulkWrite().
1321 * @param aCapacity The requested capacity. The return value
1322 * will be greater than or equal to this value.
1323 * @param aPrefixToPreserve The number of code units at the start
1324 * of the old buffer to copy into the
1325 * new buffer.
1326 * @parem aAllowShrinking If true, an allocation may be performed
1327 * if the requested capacity is smaller
1328 * than the current capacity.
1329 * @param aSuffixLength The length, in code units, of a suffix
1330 * to move.
1331 * @param aOldSuffixStart The old start index of the suffix to
1332 * move.
1333 * @param aNewSuffixStart The new start index of the suffix to
1334 * move.
1337 mozilla::Result<size_type, nsresult> NS_FASTCALL StartBulkWriteImpl(
1338 size_type aCapacity, size_type aPrefixToPreserve = 0,
1339 bool aAllowShrinking = true, size_type aSuffixLength = 0,
1340 size_type aOldSuffixStart = 0, size_type aNewSuffixStart = 0);
1342 private:
1343 void AssignOwned(self_type&& aStr);
1344 bool AssignNonDependent(const substring_tuple_type& aTuple,
1345 size_type aTupleLength,
1346 const mozilla::fallible_t& aFallible);
1349 * Do not call this except from within FinishBulkWriteImpl() and
1350 * SetCapacity().
1352 MOZ_ALWAYS_INLINE void NS_FASTCALL
1353 FinishBulkWriteImplImpl(LengthStorage aLength) {
1354 base_string_type::mData[aLength] = char_type(0);
1355 base_string_type::mLength = aLength;
1356 #ifdef DEBUG
1357 // ifdefed in order to avoid the call to Capacity() in non-debug
1358 // builds.
1360 // Our string is mutable, so Capacity() doesn't return zero.
1361 // Capacity() doesn't include the space for the zero terminator,
1362 // but we want to unitialize that slot, too. Since we start
1363 // counting after the zero terminator the we just wrote above,
1364 // we end up overwriting the space for terminator not reflected
1365 // in the capacity number.
1366 char_traits::uninitialize(
1367 base_string_type::mData + aLength + 1,
1368 XPCOM_MIN(size_t(Capacity() - aLength), kNsStringBufferMaxPoison));
1369 #endif
1372 protected:
1374 * Restores the string to a valid state after a call to StartBulkWrite()
1375 * that returned a non-error result. The argument to this method
1376 * must be less than or equal to the value returned by the most recent
1377 * StartBulkWrite() call.
1379 void NS_FASTCALL FinishBulkWriteImpl(size_type aLength);
1382 * this function prepares a section of mData to be modified. if
1383 * necessary, this function will reallocate mData and possibly move
1384 * existing data to open up the specified section.
1386 * @param aCutStart specifies the starting offset of the section
1387 * @param aCutLength specifies the length of the section to be replaced
1388 * @param aNewLength specifies the length of the new section
1390 * for example, suppose mData contains the string "abcdef" then
1392 * ReplacePrep(2, 3, 4);
1394 * would cause mData to look like "ab____f" where the characters
1395 * indicated by '_' have an unspecified value and can be freely
1396 * modified. this function will null-terminate mData upon return.
1398 * this function returns false if is unable to allocate sufficient
1399 * memory.
1401 [[nodiscard]] bool ReplacePrep(index_type aCutStart, size_type aCutLength,
1402 size_type aNewLength);
1404 [[nodiscard]] bool NS_FASTCALL ReplacePrepInternal(index_type aCutStart,
1405 size_type aCutLength,
1406 size_type aNewFragLength,
1407 size_type aNewTotalLength);
1410 * returns the number of writable storage units starting at mData.
1411 * the value does not include space for the null-terminator character.
1413 * NOTE: this function returns 0 if mData is immutable (or the buffer
1414 * is 0-sized).
1416 size_type NS_FASTCALL Capacity() const;
1419 * this helper function can be called prior to directly manipulating
1420 * the contents of mData. see, for example, BeginWriting.
1422 [[nodiscard]] bool NS_FASTCALL
1423 EnsureMutable(size_type aNewLen = size_type(-1));
1425 void NS_FASTCALL ReplaceLiteral(index_type aCutStart, size_type aCutLength,
1426 const char_type* aData, size_type aLength);
1428 public:
1429 // NOTE: this method is declared public _only_ for convenience for
1430 // callers who don't have access to the original nsLiteralString_CharT.
1431 void NS_FASTCALL AssignLiteral(const char_type* aData, size_type aLength);
1434 extern template class nsTSubstring<char>;
1435 extern template class nsTSubstring<char16_t>;
1437 static_assert(sizeof(nsTSubstring<char>) ==
1438 sizeof(mozilla::detail::nsTStringRepr<char>),
1439 "Don't add new data fields to nsTSubstring_CharT. "
1440 "Add to nsTStringRepr<T> instead.");
1442 #include "nsCharSeparatedTokenizer.h"
1443 #include "nsTDependentSubstring.h"
1446 * Span integration
1448 namespace mozilla {
1449 Span(const nsTSubstring<char>&) -> Span<const char>;
1450 Span(const nsTSubstring<char16_t>&) -> Span<const char16_t>;
1452 } // namespace mozilla
1454 #endif