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"
11 #include "nsTSubstring.h"
14 * This is the canonical null-terminated string class. All subclasses
15 * promise null-terminated storage. Instances of this class allocate
16 * strings on the heap.
19 * nsString for wide characters
20 * nsCString for narrow characters
22 * This class is also known as nsAFlat[C]String, where "flat" is used
23 * to denote a null-terminated string.
26 class nsTString
: public nsTSubstring
<T
> {
28 typedef nsTString
<T
> self_type
;
31 // bindgen w/ clang 3.9 at least chokes on a typedef, but using is okay.
32 using typename nsTSubstring
<T
>::substring_type
;
34 // On the other hand msvc chokes on the using statement. It seems others
35 // don't care either way so we lump them in here.
36 typedef typename nsTSubstring
<T
>::substring_type substring_type
;
39 typedef typename
substring_type::fallible_t fallible_t
;
41 typedef typename
substring_type::char_type char_type
;
42 typedef typename
substring_type::char_traits char_traits
;
44 typename
substring_type::incompatible_char_type incompatible_char_type
;
46 typedef typename
substring_type::substring_tuple_type substring_tuple_type
;
48 typedef typename
substring_type::const_iterator const_iterator
;
49 typedef typename
substring_type::iterator iterator
;
51 typedef typename
substring_type::comparator_type comparator_type
;
53 typedef typename
substring_type::const_char_iterator const_char_iterator
;
55 typedef typename
substring_type::index_type index_type
;
56 typedef typename
substring_type::size_type size_type
;
58 // These are only for internal use within the string classes:
59 typedef typename
substring_type::DataFlags DataFlags
;
60 typedef typename
substring_type::ClassFlags ClassFlags
;
67 nsTString() : substring_type(ClassFlags::NULL_TERMINATED
) {}
69 explicit nsTString(const char_type
* aData
, size_type aLength
= size_type(-1))
70 : substring_type(ClassFlags::NULL_TERMINATED
) {
71 this->Assign(aData
, aLength
);
74 explicit nsTString(mozilla::Span
<const char_type
> aData
)
75 : nsTString(aData
.Elements(), aData
.Length()) {}
77 #if defined(MOZ_USE_CHAR16_WRAPPER)
78 template <typename Q
= T
, typename EnableIfChar16
= mozilla::Char16OnlyT
<Q
>>
79 explicit nsTString(char16ptr_t aStr
, size_type aLength
= size_type(-1))
80 : substring_type(ClassFlags::NULL_TERMINATED
) {
81 this->Assign(static_cast<const char16_t
*>(aStr
), aLength
);
85 nsTString(const self_type
& aStr
)
86 : substring_type(ClassFlags::NULL_TERMINATED
) {
90 nsTString(self_type
&& aStr
) : substring_type(ClassFlags::NULL_TERMINATED
) {
91 this->Assign(std::move(aStr
));
94 MOZ_IMPLICIT
nsTString(const substring_tuple_type
& aTuple
)
95 : substring_type(ClassFlags::NULL_TERMINATED
) {
99 explicit nsTString(const substring_type
& aReadable
)
100 : substring_type(ClassFlags::NULL_TERMINATED
) {
101 this->Assign(aReadable
);
104 explicit nsTString(substring_type
&& aReadable
)
105 : substring_type(ClassFlags::NULL_TERMINATED
) {
106 this->Assign(std::move(aReadable
));
109 // |operator=| does not inherit, so we must define our own
110 self_type
& operator=(char_type aChar
) {
114 self_type
& operator=(const char_type
* aData
) {
118 self_type
& operator=(const self_type
& aStr
) {
122 self_type
& operator=(self_type
&& aStr
) {
123 this->Assign(std::move(aStr
));
126 #if defined(MOZ_USE_CHAR16_WRAPPER)
127 template <typename Q
= T
, typename EnableIfChar16
= mozilla::Char16OnlyT
<Q
>>
128 self_type
& operator=(const char16ptr_t aStr
) {
129 this->Assign(static_cast<const char16_t
*>(aStr
));
133 self_type
& operator=(const substring_type
& aStr
) {
137 self_type
& operator=(substring_type
&& aStr
) {
138 this->Assign(std::move(aStr
));
141 self_type
& operator=(const substring_tuple_type
& aTuple
) {
142 this->Assign(aTuple
);
147 * returns the null-terminated string
150 template <typename U
, typename Dummy
>
152 typedef const U
* type
;
154 #if defined(MOZ_USE_CHAR16_WRAPPER)
155 template <typename Dummy
>
156 struct raw_type
<char16_t
, Dummy
> {
157 typedef char16ptr_t type
;
161 MOZ_NO_DANGLING_ON_TEMPORARIES typename raw_type
<T
, int>::type
get() const {
166 * returns character at specified index.
168 * NOTE: unlike nsTSubstring::CharAt, this function allows you to index
169 * the null terminator character.
172 char_type
CharAt(index_type aIndex
) const {
173 NS_ASSERTION(aIndex
<= this->mLength
, "index exceeds allowable range");
174 return this->mData
[aIndex
];
177 char_type
operator[](index_type aIndex
) const { return CharAt(aIndex
); }
179 #if MOZ_STRING_WITH_OBSOLETE_API
182 * Search for the given substring within this string.
184 * @param aString is substring to be sought in this
185 * @param aIgnoreCase selects case sensitivity
186 * @param aOffset tells us where in this string to start searching
187 * @param aCount tells us how far from the offset we are to search. Use
188 * -1 to search the whole string.
189 * @return offset in string, or kNotFound
192 int32_t Find(const nsTString
<char>& aString
, bool aIgnoreCase
= false,
193 int32_t aOffset
= 0, int32_t aCount
= -1) const;
194 int32_t Find(const char* aString
, bool aIgnoreCase
= false,
195 int32_t aOffset
= 0, int32_t aCount
= -1) const;
197 template <typename Q
= T
, typename EnableIfChar16
= mozilla::Char16OnlyT
<Q
>>
198 int32_t Find(const self_type
& aString
, int32_t aOffset
= 0,
199 int32_t aCount
= -1) const;
200 template <typename Q
= T
, typename EnableIfChar16
= mozilla::Char16OnlyT
<Q
>>
201 int32_t Find(const char_type
* aString
, int32_t aOffset
= 0,
202 int32_t aCount
= -1) const;
203 # ifdef MOZ_USE_CHAR16_WRAPPER
204 template <typename Q
= T
, typename EnableIfChar16
= mozilla::Char16OnlyT
<Q
>>
205 int32_t Find(char16ptr_t aString
, int32_t aOffset
= 0,
206 int32_t aCount
= -1) const {
207 return Find(static_cast<const char16_t
*>(aString
), aOffset
, aCount
);
212 * This methods scans the string backwards, looking for the given string
214 * @param aString is substring to be sought in this
215 * @param aIgnoreCase tells us whether or not to do caseless compare
216 * @param aOffset tells us where in this string to start searching.
217 * Use -1 to search from the end of the string.
218 * @param aCount tells us how many iterations to make starting at the
220 * @return offset in string, or kNotFound
223 // Case aIgnoreCase option only with char versions
224 int32_t RFind(const nsTString
<char>& aString
, bool aIgnoreCase
= false,
225 int32_t aOffset
= -1, int32_t aCount
= -1) const;
226 int32_t RFind(const char* aCString
, bool aIgnoreCase
= false,
227 int32_t aOffset
= -1, int32_t aCount
= -1) const;
229 template <typename Q
= T
, typename EnableIfChar16
= mozilla::Char16OnlyT
<Q
>>
230 int32_t RFind(const self_type
& aString
, int32_t aOffset
= -1,
231 int32_t aCount
= -1) const;
232 template <typename Q
= T
, typename EnableIfChar16
= mozilla::Char16OnlyT
<Q
>>
233 int32_t RFind(const char_type
* aString
, int32_t aOffset
= -1,
234 int32_t aCount
= -1) const;
237 * Search for given char within this string
239 * @param aChar is the character to search for
240 * @param aOffset tells us where in this string to start searching
241 * @param aCount tells us how far from the offset we are to search.
242 * Use -1 to search the whole string.
243 * @return offset in string, or kNotFound
246 // int32_t FindChar( char16_t aChar, int32_t aOffset=0,
247 // int32_t aCount=-1 ) const;
248 int32_t RFindChar(char16_t aChar
, int32_t aOffset
= -1,
249 int32_t aCount
= -1) const;
252 * This method searches this string for the first character found in
255 * @param aString contains set of chars to be found
256 * @param aOffset tells us where in this string to start searching
257 * (counting from left)
258 * @return offset in string, or kNotFound
261 int32_t FindCharInSet(const char_type
* aString
, int32_t aOffset
= 0) const;
262 int32_t FindCharInSet(const self_type
& aString
, int32_t aOffset
= 0) const {
263 return FindCharInSet(aString
.get(), aOffset
);
266 template <typename Q
= T
, typename EnableIfChar16
= mozilla::Char16OnlyT
<Q
>>
267 int32_t FindCharInSet(const char* aSet
, int32_t aOffset
= 0) const;
270 * This method searches this string for the last character found in
273 * @param aString contains set of chars to be found
274 * @param aOffset tells us where in this string to start searching
275 * (counting from left)
276 * @return offset in string, or kNotFound
279 int32_t RFindCharInSet(const char_type
* aString
, int32_t aOffset
= -1) const;
280 int32_t RFindCharInSet(const self_type
& aString
, int32_t aOffset
= -1) const {
281 return RFindCharInSet(aString
.get(), aOffset
);
285 * Perform string to double-precision float conversion.
287 * @param aErrorCode will contain error if one occurs
288 * @return double-precision float rep of string value
290 double ToDouble(nsresult
* aErrorCode
) const;
293 * Perform string to single-precision float conversion.
295 * @param aErrorCode will contain error if one occurs
296 * @return single-precision float rep of string value
298 float ToFloat(nsresult
* aErrorCode
) const;
301 * Similar to above ToDouble and ToFloat but allows trailing characters that
304 double ToDoubleAllowTrailingChars(nsresult
* aErrorCode
) const;
305 float ToFloatAllowTrailingChars(nsresult
* aErrorCode
) const;
308 * |Left|, |Mid|, and |Right| are annoying signatures that seem better almost
309 * any _other_ way than they are now. Consider these alternatives
311 * // ...a member function that returns a |Substring|
312 * aWritable = aReadable.Left(17);
313 * // ...a global function that returns a |Substring|
314 * aWritable = Left(aReadable, 17);
315 * // ...a global function that does the assignment
316 * Left(aReadable, 17, aWritable);
318 * as opposed to the current signature
320 * // ...a member function that does the assignment
321 * aReadable.Left(aWritable, 17);
323 * or maybe just stamping them out in favor of |Substring|, they are just
324 * duplicate functionality
326 * aWritable = Substring(aReadable, 0, 17);
329 size_type
Mid(self_type
& aResult
, index_type aStartPos
,
330 size_type aCount
) const;
332 size_type
Left(self_type
& aResult
, size_type aCount
) const {
333 return Mid(aResult
, 0, aCount
);
336 size_type
Right(self_type
& aResult
, size_type aCount
) const {
337 aCount
= XPCOM_MIN(this->mLength
, aCount
);
338 return Mid(aResult
, this->mLength
- aCount
, aCount
);
342 * Set a char inside this string at given index
344 * @param aChar is the char you want to write into this string
345 * @param anIndex is the ofs where you want to write the given char
346 * @return TRUE if successful
349 bool SetCharAt(char16_t aChar
, uint32_t aIndex
);
352 * These methods are used to remove all occurrences of the
353 * characters found in aSet from this string.
355 * @param aSet -- characters to be cut from this
357 void StripChars(const char_type
* aSet
);
359 template <typename Q
= T
, typename EnableIfChar16
= mozilla::Char16OnlyT
<Q
>>
360 bool StripChars(const incompatible_char_type
* aSet
, const fallible_t
&);
362 template <typename Q
= T
, typename EnableIfChar16
= mozilla::Char16OnlyT
<Q
>>
363 void StripChars(const incompatible_char_type
* aSet
);
366 * This method strips whitespace throughout the string.
368 void StripWhitespace();
369 bool StripWhitespace(const fallible_t
&);
372 * swaps occurence of 1 string for another
375 void ReplaceChar(char_type aOldChar
, char_type aNewChar
);
376 void ReplaceChar(const char_type
* aSet
, char_type aNewChar
);
378 template <typename Q
= T
, typename EnableIfChar16
= mozilla::Char16OnlyT
<Q
>>
379 void ReplaceChar(const char* aSet
, char16_t aNewChar
);
382 * Replace all occurrences of aTarget with aNewValue.
383 * The complexity of this function is O(n+m), n being the length of the string
384 * and m being the length of aNewValue.
386 void ReplaceSubstring(const self_type
& aTarget
, const self_type
& aNewValue
);
387 void ReplaceSubstring(const char_type
* aTarget
, const char_type
* aNewValue
);
388 [[nodiscard
]] bool ReplaceSubstring(const self_type
& aTarget
,
389 const self_type
& aNewValue
,
391 [[nodiscard
]] bool ReplaceSubstring(const char_type
* aTarget
,
392 const char_type
* aNewValue
,
396 * This method trims characters found in aTrimSet from
397 * either end of the underlying string.
399 * @param aSet -- contains chars to be trimmed from both ends
400 * @param aEliminateLeading
401 * @param aEliminateTrailing
402 * @param aIgnoreQuotes -- if true, causes surrounding quotes to be ignored
405 void Trim(const char* aSet
, bool aEliminateLeading
= true,
406 bool aEliminateTrailing
= true, bool aIgnoreQuotes
= false);
409 * This method strips whitespace from string.
410 * You can control whether whitespace is yanked from start and end of
413 * @param aEliminateLeading controls stripping of leading ws
414 * @param aEliminateTrailing controls stripping of trailing ws
416 void CompressWhitespace(bool aEliminateLeading
= true,
417 bool aEliminateTrailing
= true);
419 #endif // !MOZ_STRING_WITH_OBSOLETE_API
422 * Allow this string to be bound to a character buffer
423 * until the string is rebound or mutated; the caller
424 * must ensure that the buffer outlives the string.
426 void Rebind(const char_type
* aData
, size_type aLength
);
429 * verify restrictions for dependent strings
431 void AssertValidDependentString() {
432 MOZ_ASSERT(this->mData
, "nsTDependentString must wrap a non-NULL buffer");
433 MOZ_ASSERT(this->mLength
!= size_type(-1),
434 "nsTDependentString has bogus length");
435 MOZ_DIAGNOSTIC_ASSERT(this->mData
[substring_type::mLength
] == 0,
436 "nsTDependentString must wrap only null-terminated "
437 "strings. You are probably looking for "
438 "nsTDependentSubstring.");
442 // allow subclasses to initialize fields directly
443 nsTString(char_type
* aData
, size_type aLength
, DataFlags aDataFlags
,
444 ClassFlags aClassFlags
)
445 : substring_type(aData
, aLength
, aDataFlags
,
446 aClassFlags
| ClassFlags::NULL_TERMINATED
) {}
448 friend const nsTString
<char>& VoidCString();
449 friend const nsTString
<char16_t
>& VoidString();
451 // Used by Null[C]String.
452 explicit nsTString(DataFlags aDataFlags
)
453 : substring_type(char_traits::sEmptyBuffer
, 0,
454 aDataFlags
| DataFlags::TERMINATED
,
455 ClassFlags::NULL_TERMINATED
) {}
457 enum class TrailingCharsPolicy
{
461 // Utility function for ToDouble and ToDoubleAllowTrailingChars.
462 double ToDouble(TrailingCharsPolicy aTrailingCharsPolicy
,
463 nsresult
* aErrorCode
) const;
466 uint32_t mBegin
, mLength
;
467 Segment(uint32_t aBegin
, uint32_t aLength
)
468 : mBegin(aBegin
), mLength(aLength
) {}
472 // TODO(erahm): Do something with ToDouble so that we can extern the
473 // nsTString templates.
474 // extern template class nsTString<char>;
475 // extern template class nsTString<char16_t>;
480 * Subclass of nsTString that adds support for stack-based string
481 * allocation. It is normally not a good idea to use this class on the
482 * heap, because it will allocate space which may be wasted if the string
483 * it contains is significantly smaller or any larger than 64 characters.
486 * nsAutoStringN / nsTAutoString for wide characters
487 * nsAutoCStringN / nsTAutoCString for narrow characters
489 template <typename T
, size_t N
>
490 class MOZ_NON_MEMMOVABLE nsTAutoStringN
: public nsTString
<T
> {
492 typedef nsTAutoStringN
<T
, N
> self_type
;
494 typedef nsTString
<T
> base_string_type
;
495 typedef typename
base_string_type::string_type string_type
;
496 typedef typename
base_string_type::char_type char_type
;
497 typedef typename
base_string_type::char_traits char_traits
;
498 typedef typename
base_string_type::substring_type substring_type
;
499 typedef typename
base_string_type::size_type size_type
;
500 typedef typename
base_string_type::substring_tuple_type substring_tuple_type
;
502 // These are only for internal use within the string classes:
503 typedef typename
base_string_type::DataFlags DataFlags
;
504 typedef typename
base_string_type::ClassFlags ClassFlags
;
512 : string_type(mStorage
, 0, DataFlags::TERMINATED
| DataFlags::INLINE
,
514 mInlineCapacity(N
- 1) {
516 mStorage
[0] = char_type(0);
519 explicit nsTAutoStringN(char_type aChar
) : self_type() {
523 explicit nsTAutoStringN(const char_type
* aData
,
524 size_type aLength
= size_type(-1))
526 this->Assign(aData
, aLength
);
529 #if defined(MOZ_USE_CHAR16_WRAPPER)
530 template <typename Q
= T
, typename EnableIfChar16
= mozilla::Char16OnlyT
<Q
>>
531 explicit nsTAutoStringN(char16ptr_t aData
, size_type aLength
= size_type(-1))
532 : self_type(static_cast<const char16_t
*>(aData
), aLength
) {}
535 nsTAutoStringN(const self_type
& aStr
) : self_type() { this->Assign(aStr
); }
537 nsTAutoStringN(self_type
&& aStr
) : self_type() {
538 this->Assign(std::move(aStr
));
541 explicit nsTAutoStringN(const substring_type
& aStr
) : self_type() {
545 explicit nsTAutoStringN(substring_type
&& aStr
) : self_type() {
546 this->Assign(std::move(aStr
));
549 MOZ_IMPLICIT
nsTAutoStringN(const substring_tuple_type
& aTuple
)
551 this->Assign(aTuple
);
554 // |operator=| does not inherit, so we must define our own
555 self_type
& operator=(char_type aChar
) {
559 self_type
& operator=(const char_type
* aData
) {
563 #if defined(MOZ_USE_CHAR16_WRAPPER)
564 template <typename Q
= T
, typename EnableIfChar16
= mozilla::Char16OnlyT
<Q
>>
565 self_type
& operator=(char16ptr_t aStr
) {
570 self_type
& operator=(const self_type
& aStr
) {
574 self_type
& operator=(self_type
&& aStr
) {
575 this->Assign(std::move(aStr
));
578 self_type
& operator=(const substring_type
& aStr
) {
582 self_type
& operator=(substring_type
&& aStr
) {
583 this->Assign(std::move(aStr
));
586 self_type
& operator=(const substring_tuple_type
& aTuple
) {
587 this->Assign(aTuple
);
591 static const size_t kStorageSize
= N
;
594 friend class nsTSubstring
<T
>;
596 const size_type mInlineCapacity
;
599 char_type mStorage
[N
];
602 // Externs for the most common nsTAutoStringN variations.
603 extern template class nsTAutoStringN
<char, 64>;
604 extern template class nsTAutoStringN
<char16_t
, 64>;
607 // nsAutoString stores pointers into itself which are invalidated when an
608 // nsTArray is resized, so nsTArray must not be instantiated with nsAutoString
612 class nsTArrayElementTraits
;
613 template <typename T
>
614 class nsTArrayElementTraits
<nsTAutoString
<T
>> {
617 struct Dont_Instantiate_nsTArray_of
;
619 struct Instead_Use_nsTArray_of
;
621 static Dont_Instantiate_nsTArray_of
<nsTAutoString
<T
>>* Construct(
622 Instead_Use_nsTArray_of
<nsTString
<T
>>* aE
) {
626 static Dont_Instantiate_nsTArray_of
<nsTAutoString
<T
>>* Construct(
627 Instead_Use_nsTArray_of
<nsTString
<T
>>* aE
, const A
& aArg
) {
630 template <class... Args
>
631 static Dont_Instantiate_nsTArray_of
<nsTAutoString
<T
>>* Construct(
632 Instead_Use_nsTArray_of
<nsTString
<T
>>* aE
, Args
&&... aArgs
) {
635 static Dont_Instantiate_nsTArray_of
<nsTAutoString
<T
>>* Destruct(
636 Instead_Use_nsTArray_of
<nsTString
<T
>>* aE
) {
642 * getter_Copies support for adopting raw string out params that are
643 * heap-allocated, e.g.:
646 * void GetBlah(char** aStr)
648 * *aStr = strdup(gStr);
651 * // This works, but is clumsy.
665 * GetBlah(getter_Copies(str));
669 template <typename T
>
670 class MOZ_STACK_CLASS nsTGetterCopies
{
674 explicit nsTGetterCopies(nsTSubstring
<T
>& aStr
)
675 : mString(aStr
), mData(nullptr) {}
678 mString
.Adopt(mData
); // OK if mData is null
681 operator char_type
**() { return &mData
; }
684 nsTSubstring
<T
>& mString
;
688 // See the comment above nsTGetterCopies_CharT for how to use this.
689 template <typename T
>
690 inline nsTGetterCopies
<T
> getter_Copies(nsTSubstring
<T
>& aString
) {
691 return nsTGetterCopies
<T
>(aString
);