mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-13 23:17:57 +00:00
1141 lines
33 KiB
C++
1141 lines
33 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
// IWYU pragma: private, include "nsString.h"
|
|
|
|
#include "mozilla/Casting.h"
|
|
#include "mozilla/MemoryReporting.h"
|
|
|
|
#ifndef MOZILLA_INTERNAL_API
|
|
#error Cannot use internal string classes without MOZILLA_INTERNAL_API defined. Use the frozen header nsStringAPI.h instead.
|
|
#endif
|
|
|
|
/**
|
|
* The base for string comparators
|
|
*/
|
|
class nsTStringComparator_CharT
|
|
{
|
|
public:
|
|
typedef CharT char_type;
|
|
|
|
nsTStringComparator_CharT()
|
|
{
|
|
}
|
|
|
|
virtual int operator()(const char_type*, const char_type*,
|
|
uint32_t, uint32_t) const = 0;
|
|
};
|
|
|
|
|
|
/**
|
|
* The default string comparator (case-sensitive comparision)
|
|
*/
|
|
class nsTDefaultStringComparator_CharT
|
|
: public nsTStringComparator_CharT
|
|
{
|
|
public:
|
|
typedef CharT char_type;
|
|
|
|
nsTDefaultStringComparator_CharT()
|
|
{
|
|
}
|
|
|
|
virtual int operator()(const char_type*, const char_type*,
|
|
uint32_t, uint32_t) const;
|
|
};
|
|
|
|
/**
|
|
* nsTSubstring is the most abstract class in the string hierarchy. It
|
|
* represents a single contiguous array of characters, which may or may not
|
|
* be null-terminated. This type is not instantiated directly. A sub-class
|
|
* is instantiated instead. For example, see nsTString.
|
|
*
|
|
* NAMES:
|
|
* nsAString for wide characters
|
|
* nsACString for narrow characters
|
|
*
|
|
* Many of the accessors on nsTSubstring are inlined as an optimization.
|
|
*/
|
|
class nsTSubstring_CharT
|
|
{
|
|
public:
|
|
typedef mozilla::fallible_t fallible_t;
|
|
|
|
typedef CharT char_type;
|
|
|
|
typedef nsCharTraits<char_type> char_traits;
|
|
typedef char_traits::incompatible_char_type incompatible_char_type;
|
|
|
|
typedef nsTSubstring_CharT self_type;
|
|
typedef self_type abstract_string_type;
|
|
typedef self_type base_string_type;
|
|
|
|
typedef self_type substring_type;
|
|
typedef nsTSubstringTuple_CharT substring_tuple_type;
|
|
typedef nsTString_CharT string_type;
|
|
|
|
typedef nsReadingIterator<char_type> const_iterator;
|
|
typedef nsWritingIterator<char_type> iterator;
|
|
|
|
typedef nsTStringComparator_CharT comparator_type;
|
|
|
|
typedef char_type* char_iterator;
|
|
typedef const char_type* const_char_iterator;
|
|
|
|
typedef uint32_t size_type;
|
|
typedef uint32_t index_type;
|
|
|
|
public:
|
|
|
|
// this acts like a virtual destructor
|
|
~nsTSubstring_CharT()
|
|
{
|
|
Finalize();
|
|
}
|
|
|
|
/**
|
|
* reading iterators
|
|
*/
|
|
|
|
const_char_iterator BeginReading() const
|
|
{
|
|
return mData;
|
|
}
|
|
const_char_iterator EndReading() const
|
|
{
|
|
return mData + mLength;
|
|
}
|
|
|
|
/**
|
|
* deprecated reading iterators
|
|
*/
|
|
|
|
const_iterator& BeginReading(const_iterator& aIter) const
|
|
{
|
|
aIter.mStart = mData;
|
|
aIter.mEnd = mData + mLength;
|
|
aIter.mPosition = aIter.mStart;
|
|
return aIter;
|
|
}
|
|
|
|
const_iterator& EndReading(const_iterator& aIter) const
|
|
{
|
|
aIter.mStart = mData;
|
|
aIter.mEnd = mData + mLength;
|
|
aIter.mPosition = aIter.mEnd;
|
|
return aIter;
|
|
}
|
|
|
|
const_char_iterator& BeginReading(const_char_iterator& aIter) const
|
|
{
|
|
return aIter = mData;
|
|
}
|
|
|
|
const_char_iterator& EndReading(const_char_iterator& aIter) const
|
|
{
|
|
return aIter = mData + mLength;
|
|
}
|
|
|
|
|
|
/**
|
|
* writing iterators
|
|
*/
|
|
|
|
char_iterator BeginWriting()
|
|
{
|
|
if (!EnsureMutable()) {
|
|
NS_ABORT_OOM(mLength);
|
|
}
|
|
|
|
return mData;
|
|
}
|
|
|
|
char_iterator BeginWriting(const fallible_t&)
|
|
{
|
|
return EnsureMutable() ? mData : char_iterator(0);
|
|
}
|
|
|
|
char_iterator EndWriting()
|
|
{
|
|
if (!EnsureMutable()) {
|
|
NS_ABORT_OOM(mLength);
|
|
}
|
|
|
|
return mData + mLength;
|
|
}
|
|
|
|
char_iterator EndWriting(const fallible_t&)
|
|
{
|
|
return EnsureMutable() ? (mData + mLength) : char_iterator(0);
|
|
}
|
|
|
|
char_iterator& BeginWriting(char_iterator& aIter)
|
|
{
|
|
return aIter = BeginWriting();
|
|
}
|
|
|
|
char_iterator& BeginWriting(char_iterator& aIter, const fallible_t&)
|
|
{
|
|
return aIter = BeginWriting(fallible_t());
|
|
}
|
|
|
|
char_iterator& EndWriting(char_iterator& aIter)
|
|
{
|
|
return aIter = EndWriting();
|
|
}
|
|
|
|
char_iterator& EndWriting(char_iterator& aIter, const fallible_t&)
|
|
{
|
|
return aIter = EndWriting(fallible_t());
|
|
}
|
|
|
|
/**
|
|
* deprecated writing iterators
|
|
*/
|
|
|
|
iterator& BeginWriting(iterator& aIter)
|
|
{
|
|
char_type* data = BeginWriting();
|
|
aIter.mStart = data;
|
|
aIter.mEnd = data + mLength;
|
|
aIter.mPosition = aIter.mStart;
|
|
return aIter;
|
|
}
|
|
|
|
iterator& EndWriting(iterator& aIter)
|
|
{
|
|
char_type* data = BeginWriting();
|
|
aIter.mStart = data;
|
|
aIter.mEnd = data + mLength;
|
|
aIter.mPosition = aIter.mEnd;
|
|
return aIter;
|
|
}
|
|
|
|
/**
|
|
* accessors
|
|
*/
|
|
|
|
// returns pointer to string data (not necessarily null-terminated)
|
|
#if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER)
|
|
char16ptr_t Data() const
|
|
#else
|
|
const char_type* Data() const
|
|
#endif
|
|
{
|
|
return mData;
|
|
}
|
|
|
|
size_type Length() const
|
|
{
|
|
return mLength;
|
|
}
|
|
|
|
uint32_t Flags() const
|
|
{
|
|
return mFlags;
|
|
}
|
|
|
|
bool IsEmpty() const
|
|
{
|
|
return mLength == 0;
|
|
}
|
|
|
|
bool IsLiteral() const
|
|
{
|
|
return (mFlags & F_LITERAL) != 0;
|
|
}
|
|
|
|
bool IsVoid() const
|
|
{
|
|
return (mFlags & F_VOIDED) != 0;
|
|
}
|
|
|
|
bool IsTerminated() const
|
|
{
|
|
return (mFlags & F_TERMINATED) != 0;
|
|
}
|
|
|
|
char_type CharAt(index_type aIndex) const
|
|
{
|
|
NS_ASSERTION(aIndex < mLength, "index exceeds allowable range");
|
|
return mData[aIndex];
|
|
}
|
|
|
|
char_type operator[](index_type aIndex) const
|
|
{
|
|
return CharAt(aIndex);
|
|
}
|
|
|
|
char_type First() const
|
|
{
|
|
NS_ASSERTION(mLength > 0, "|First()| called on an empty string");
|
|
return mData[0];
|
|
}
|
|
|
|
inline char_type Last() const
|
|
{
|
|
NS_ASSERTION(mLength > 0, "|Last()| called on an empty string");
|
|
return mData[mLength - 1];
|
|
}
|
|
|
|
size_type NS_FASTCALL CountChar(char_type) const;
|
|
int32_t NS_FASTCALL FindChar(char_type, index_type aOffset = 0) const;
|
|
|
|
|
|
/**
|
|
* equality
|
|
*/
|
|
|
|
bool NS_FASTCALL Equals(const self_type&) const;
|
|
bool NS_FASTCALL Equals(const self_type&, const comparator_type&) const;
|
|
|
|
bool NS_FASTCALL Equals(const char_type* aData) const;
|
|
bool NS_FASTCALL Equals(const char_type* aData,
|
|
const comparator_type& aComp) const;
|
|
|
|
#if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER)
|
|
bool NS_FASTCALL Equals(char16ptr_t aData) const
|
|
{
|
|
return Equals(static_cast<const char16_t*>(aData));
|
|
}
|
|
bool NS_FASTCALL Equals(char16ptr_t aData, const comparator_type& aComp) const
|
|
{
|
|
return Equals(static_cast<const char16_t*>(aData), aComp);
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* An efficient comparison with ASCII that can be used even
|
|
* for wide strings. Call this version when you know the
|
|
* length of 'data'.
|
|
*/
|
|
bool NS_FASTCALL EqualsASCII(const char* aData, size_type aLen) const;
|
|
/**
|
|
* An efficient comparison with ASCII that can be used even
|
|
* for wide strings. Call this version when 'data' is
|
|
* null-terminated.
|
|
*/
|
|
bool NS_FASTCALL EqualsASCII(const char* aData) const;
|
|
|
|
// EqualsLiteral must ONLY be applied to an actual literal string, or
|
|
// a char array *constant* declared without an explicit size.
|
|
// Do not attempt to use it with a regular char* pointer, or with a
|
|
// non-constant char array variable. Use EqualsASCII for them.
|
|
// The template trick to acquire the array length at compile time without
|
|
// using a macro is due to Corey Kosak, with much thanks.
|
|
template<int N>
|
|
inline bool EqualsLiteral(const char (&aStr)[N]) const
|
|
{
|
|
return EqualsASCII(aStr, N - 1);
|
|
}
|
|
|
|
// The LowerCaseEquals methods compare the ASCII-lowercase version of
|
|
// this string (lowercasing only ASCII uppercase characters) to some
|
|
// ASCII/Literal string. The ASCII string is *not* lowercased for
|
|
// you. If you compare to an ASCII or literal string that contains an
|
|
// uppercase character, it is guaranteed to return false. We will
|
|
// throw assertions too.
|
|
bool NS_FASTCALL LowerCaseEqualsASCII(const char* aData,
|
|
size_type aLen) const;
|
|
bool NS_FASTCALL LowerCaseEqualsASCII(const char* aData) const;
|
|
|
|
// LowerCaseEqualsLiteral must ONLY be applied to an actual
|
|
// literal string, or a char array *constant* declared without an
|
|
// explicit size. Do not attempt to use it with a regular char*
|
|
// pointer, or with a non-constant char array variable. Use
|
|
// LowerCaseEqualsASCII for them.
|
|
template<int N>
|
|
inline bool LowerCaseEqualsLiteral(const char (&aStr)[N]) const
|
|
{
|
|
return LowerCaseEqualsASCII(aStr, N - 1);
|
|
}
|
|
|
|
/**
|
|
* assignment
|
|
*/
|
|
|
|
void NS_FASTCALL Assign(char_type aChar);
|
|
NS_WARN_UNUSED_RESULT bool NS_FASTCALL Assign(char_type aChar,
|
|
const fallible_t&);
|
|
|
|
void NS_FASTCALL Assign(const char_type* aData);
|
|
void NS_FASTCALL Assign(const char_type* aData, size_type aLength);
|
|
NS_WARN_UNUSED_RESULT bool NS_FASTCALL Assign(const char_type* aData,
|
|
size_type aLength,
|
|
const fallible_t&);
|
|
|
|
void NS_FASTCALL Assign(const self_type&);
|
|
NS_WARN_UNUSED_RESULT bool NS_FASTCALL Assign(const self_type&,
|
|
const fallible_t&);
|
|
|
|
void NS_FASTCALL Assign(const substring_tuple_type&);
|
|
NS_WARN_UNUSED_RESULT bool NS_FASTCALL Assign(const substring_tuple_type&,
|
|
const fallible_t&);
|
|
|
|
#if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER)
|
|
void Assign(char16ptr_t aData)
|
|
{
|
|
Assign(static_cast<const char16_t*>(aData));
|
|
}
|
|
|
|
NS_WARN_UNUSED_RESULT bool Assign(char16ptr_t aData, const fallible_t&)
|
|
{
|
|
return Assign(static_cast<const char16_t*>(aData), fallible_t());
|
|
}
|
|
|
|
void Assign(char16ptr_t aData, size_type aLength)
|
|
{
|
|
Assign(static_cast<const char16_t*>(aData), aLength);
|
|
}
|
|
|
|
NS_WARN_UNUSED_RESULT bool Assign(char16ptr_t aData, size_type aLength,
|
|
const fallible_t&)
|
|
{
|
|
return Assign(static_cast<const char16_t*>(aData), aLength, fallible_t());
|
|
}
|
|
#endif
|
|
|
|
void NS_FASTCALL AssignASCII(const char* aData, size_type aLength);
|
|
NS_WARN_UNUSED_RESULT bool NS_FASTCALL AssignASCII(const char* aData,
|
|
size_type aLength,
|
|
const fallible_t&);
|
|
|
|
void NS_FASTCALL AssignASCII(const char* aData)
|
|
{
|
|
AssignASCII(aData, mozilla::AssertedCast<size_type, size_t>(strlen(aData)));
|
|
}
|
|
NS_WARN_UNUSED_RESULT bool NS_FASTCALL AssignASCII(const char* aData,
|
|
const fallible_t&)
|
|
{
|
|
return AssignASCII(aData,
|
|
mozilla::AssertedCast<size_type, size_t>(strlen(aData)),
|
|
fallible_t());
|
|
}
|
|
|
|
// AssignLiteral must ONLY be applied to an actual literal string, or
|
|
// a char array *constant* declared without an explicit size.
|
|
// Do not attempt to use it with a regular char* pointer, or with a
|
|
// non-constant char array variable. Use AssignASCII for those.
|
|
// There are not fallible version of these methods because they only really
|
|
// apply to small allocations that we wouldn't want to check anyway.
|
|
template<int N>
|
|
void AssignLiteral(const char_type (&aStr)[N])
|
|
{
|
|
AssignLiteral(aStr, N - 1);
|
|
}
|
|
#ifdef CharT_is_PRUnichar
|
|
template<int N>
|
|
void AssignLiteral(const char (&aStr)[N])
|
|
{
|
|
AssignASCII(aStr, N - 1);
|
|
}
|
|
#endif
|
|
|
|
self_type& operator=(char_type aChar)
|
|
{
|
|
Assign(aChar);
|
|
return *this;
|
|
}
|
|
self_type& operator=(const char_type* aData)
|
|
{
|
|
Assign(aData);
|
|
return *this;
|
|
}
|
|
#if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER)
|
|
self_type& operator=(char16ptr_t aData)
|
|
{
|
|
Assign(aData);
|
|
return *this;
|
|
}
|
|
#endif
|
|
self_type& operator=(const self_type& aStr)
|
|
{
|
|
Assign(aStr);
|
|
return *this;
|
|
}
|
|
self_type& operator=(const substring_tuple_type& aTuple)
|
|
{
|
|
Assign(aTuple);
|
|
return *this;
|
|
}
|
|
|
|
void NS_FASTCALL Adopt(char_type* aData, size_type aLength = size_type(-1));
|
|
|
|
|
|
/**
|
|
* buffer manipulation
|
|
*/
|
|
|
|
void NS_FASTCALL Replace(index_type aCutStart, size_type aCutLength,
|
|
char_type aChar);
|
|
NS_WARN_UNUSED_RESULT bool NS_FASTCALL Replace(index_type aCutStart,
|
|
size_type aCutLength,
|
|
char_type aChar,
|
|
const mozilla::fallible_t&);
|
|
void NS_FASTCALL Replace(index_type aCutStart, size_type aCutLength,
|
|
const char_type* aData,
|
|
size_type aLength = size_type(-1));
|
|
NS_WARN_UNUSED_RESULT bool NS_FASTCALL Replace(index_type aCutStart,
|
|
size_type aCutLength,
|
|
const char_type* aData,
|
|
size_type aLength,
|
|
const mozilla::fallible_t&);
|
|
void Replace(index_type aCutStart, size_type aCutLength,
|
|
const self_type& aStr)
|
|
{
|
|
Replace(aCutStart, aCutLength, aStr.Data(), aStr.Length());
|
|
}
|
|
NS_WARN_UNUSED_RESULT bool Replace(index_type aCutStart,
|
|
size_type aCutLength,
|
|
const self_type& aStr,
|
|
const mozilla::fallible_t&)
|
|
{
|
|
return Replace(aCutStart, aCutLength, aStr.Data(), aStr.Length(),
|
|
mozilla::fallible_t());
|
|
}
|
|
void NS_FASTCALL Replace(index_type aCutStart, size_type aCutLength,
|
|
const substring_tuple_type& aTuple);
|
|
|
|
void NS_FASTCALL ReplaceASCII(index_type aCutStart, size_type aCutLength,
|
|
const char* aData,
|
|
size_type aLength = size_type(-1));
|
|
|
|
// ReplaceLiteral must ONLY be applied to an actual literal string.
|
|
// Do not attempt to use it with a regular char* pointer, or with a char
|
|
// array variable. Use Replace or ReplaceASCII for those.
|
|
template<int N>
|
|
void ReplaceLiteral(index_type aCutStart, size_type aCutLength,
|
|
const char_type (&aStr)[N])
|
|
{
|
|
ReplaceLiteral(aCutStart, aCutLength, aStr, N - 1);
|
|
}
|
|
|
|
void Append(char_type aChar)
|
|
{
|
|
Replace(mLength, 0, aChar);
|
|
}
|
|
NS_WARN_UNUSED_RESULT bool Append(char_type aChar,
|
|
const mozilla::fallible_t&)
|
|
{
|
|
return Replace(mLength, 0, aChar, mozilla::fallible_t());
|
|
}
|
|
void Append(const char_type* aData, size_type aLength = size_type(-1))
|
|
{
|
|
Replace(mLength, 0, aData, aLength);
|
|
}
|
|
NS_WARN_UNUSED_RESULT bool Append(const char_type* aData, size_type aLength,
|
|
const mozilla::fallible_t&)
|
|
{
|
|
return Replace(mLength, 0, aData, aLength, mozilla::fallible_t());
|
|
}
|
|
|
|
#if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER)
|
|
void Append(char16ptr_t aData, size_type aLength = size_type(-1))
|
|
{
|
|
Append(static_cast<const char16_t*>(aData), aLength);
|
|
}
|
|
#endif
|
|
|
|
void Append(const self_type& aStr)
|
|
{
|
|
Replace(mLength, 0, aStr);
|
|
}
|
|
void Append(const substring_tuple_type& aTuple)
|
|
{
|
|
Replace(mLength, 0, aTuple);
|
|
}
|
|
|
|
void AppendASCII(const char* aData, size_type aLength = size_type(-1))
|
|
{
|
|
ReplaceASCII(mLength, 0, aData, aLength);
|
|
}
|
|
|
|
/**
|
|
* Append a formatted string to the current string. Uses the format
|
|
* codes documented in prprf.h
|
|
*/
|
|
void AppendPrintf(const char* aFormat, ...);
|
|
void AppendPrintf(const char* aFormat, va_list aAp);
|
|
void AppendInt(int32_t aInteger)
|
|
{
|
|
AppendPrintf("%d", aInteger);
|
|
}
|
|
void AppendInt(int32_t aInteger, int aRadix)
|
|
{
|
|
const char* fmt = aRadix == 10 ? "%d" : aRadix == 8 ? "%o" : "%x";
|
|
AppendPrintf(fmt, aInteger);
|
|
}
|
|
void AppendInt(uint32_t aInteger)
|
|
{
|
|
AppendPrintf("%u", aInteger);
|
|
}
|
|
void AppendInt(uint32_t aInteger, int aRadix)
|
|
{
|
|
const char* fmt = aRadix == 10 ? "%u" : aRadix == 8 ? "%o" : "%x";
|
|
AppendPrintf(fmt, aInteger);
|
|
}
|
|
void AppendInt(int64_t aInteger)
|
|
{
|
|
AppendPrintf("%lld", aInteger);
|
|
}
|
|
void AppendInt(int64_t aInteger, int aRadix)
|
|
{
|
|
const char* fmt = aRadix == 10 ? "%lld" : aRadix == 8 ? "%llo" : "%llx";
|
|
AppendPrintf(fmt, aInteger);
|
|
}
|
|
void AppendInt(uint64_t aInteger)
|
|
{
|
|
AppendPrintf("%llu", aInteger);
|
|
}
|
|
void AppendInt(uint64_t aInteger, int aRadix)
|
|
{
|
|
const char* fmt = aRadix == 10 ? "%llu" : aRadix == 8 ? "%llo" : "%llx";
|
|
AppendPrintf(fmt, aInteger);
|
|
}
|
|
|
|
/**
|
|
* Append the given float to this string
|
|
*/
|
|
void NS_FASTCALL AppendFloat(float aFloat);
|
|
void NS_FASTCALL AppendFloat(double aFloat);
|
|
public:
|
|
|
|
// AppendLiteral must ONLY be applied to an actual literal string.
|
|
// Do not attempt to use it with a regular char* pointer, or with a char
|
|
// array variable. Use Append or AppendASCII for those.
|
|
template<int N>
|
|
void AppendLiteral(const char_type (&aStr)[N])
|
|
{
|
|
ReplaceLiteral(mLength, 0, aStr, N - 1);
|
|
}
|
|
#ifdef CharT_is_PRUnichar
|
|
template<int N>
|
|
void AppendLiteral(const char (&aStr)[N])
|
|
{
|
|
AppendASCII(aStr, N - 1);
|
|
}
|
|
#endif
|
|
|
|
self_type& operator+=(char_type aChar)
|
|
{
|
|
Append(aChar);
|
|
return *this;
|
|
}
|
|
self_type& operator+=(const char_type* aData)
|
|
{
|
|
Append(aData);
|
|
return *this;
|
|
}
|
|
#if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER)
|
|
self_type& operator+=(char16ptr_t aData)
|
|
{
|
|
Append(aData);
|
|
return *this;
|
|
}
|
|
#endif
|
|
self_type& operator+=(const self_type& aStr)
|
|
{
|
|
Append(aStr);
|
|
return *this;
|
|
}
|
|
self_type& operator+=(const substring_tuple_type& aTuple)
|
|
{
|
|
Append(aTuple);
|
|
return *this;
|
|
}
|
|
|
|
void Insert(char_type aChar, index_type aPos)
|
|
{
|
|
Replace(aPos, 0, aChar);
|
|
}
|
|
void Insert(const char_type* aData, index_type aPos,
|
|
size_type aLength = size_type(-1))
|
|
{
|
|
Replace(aPos, 0, aData, aLength);
|
|
}
|
|
#if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER)
|
|
void Insert(char16ptr_t aData, index_type aPos,
|
|
size_type aLength = size_type(-1))
|
|
{
|
|
Insert(static_cast<const char16_t*>(aData), aPos, aLength);
|
|
}
|
|
#endif
|
|
void Insert(const self_type& aStr, index_type aPos)
|
|
{
|
|
Replace(aPos, 0, aStr);
|
|
}
|
|
void Insert(const substring_tuple_type& aTuple, index_type aPos)
|
|
{
|
|
Replace(aPos, 0, aTuple);
|
|
}
|
|
|
|
// InsertLiteral must ONLY be applied to an actual literal string.
|
|
// Do not attempt to use it with a regular char* pointer, or with a char
|
|
// array variable. Use Insert for those.
|
|
template<int N>
|
|
void InsertLiteral(const char_type (&aStr)[N], index_type aPos)
|
|
{
|
|
ReplaceLiteral(aPos, 0, aStr, N - 1);
|
|
}
|
|
|
|
void Cut(index_type aCutStart, size_type aCutLength)
|
|
{
|
|
Replace(aCutStart, aCutLength, char_traits::sEmptyBuffer, 0);
|
|
}
|
|
|
|
|
|
/**
|
|
* buffer sizing
|
|
*/
|
|
|
|
/**
|
|
* Attempts to set the capacity to the given size in number of
|
|
* characters, without affecting the length of the string.
|
|
* There is no need to include room for the null terminator: it is
|
|
* the job of the string class.
|
|
* Also ensures that the buffer is mutable.
|
|
*/
|
|
void NS_FASTCALL SetCapacity(size_type aNewCapacity);
|
|
NS_WARN_UNUSED_RESULT bool NS_FASTCALL SetCapacity(size_type aNewCapacity,
|
|
const fallible_t&);
|
|
|
|
void NS_FASTCALL SetLength(size_type aNewLength);
|
|
NS_WARN_UNUSED_RESULT bool NS_FASTCALL SetLength(size_type aNewLength,
|
|
const fallible_t&);
|
|
|
|
void Truncate(size_type aNewLength = 0)
|
|
{
|
|
NS_ASSERTION(aNewLength <= mLength, "Truncate cannot make string longer");
|
|
SetLength(aNewLength);
|
|
}
|
|
|
|
|
|
/**
|
|
* buffer access
|
|
*/
|
|
|
|
|
|
/**
|
|
* Get a const pointer to the string's internal buffer. The caller
|
|
* MUST NOT modify the characters at the returned address.
|
|
*
|
|
* @returns The length of the buffer in characters.
|
|
*/
|
|
inline size_type GetData(const char_type** aData) const
|
|
{
|
|
*aData = mData;
|
|
return mLength;
|
|
}
|
|
|
|
/**
|
|
* Get a pointer to the string's internal buffer, optionally resizing
|
|
* the buffer first. If size_type(-1) is passed for newLen, then the
|
|
* current length of the string is used. The caller MAY modify the
|
|
* characters at the returned address (up to but not exceeding the
|
|
* length of the string).
|
|
*
|
|
* @returns The length of the buffer in characters or 0 if unable to
|
|
* satisfy the request due to low-memory conditions.
|
|
*/
|
|
size_type GetMutableData(char_type** aData, size_type aNewLen = size_type(-1))
|
|
{
|
|
if (!EnsureMutable(aNewLen)) {
|
|
NS_ABORT_OOM(aNewLen == size_type(-1) ? mLength : aNewLen);
|
|
}
|
|
|
|
*aData = mData;
|
|
return mLength;
|
|
}
|
|
|
|
size_type GetMutableData(char_type** aData, size_type aNewLen, const fallible_t&)
|
|
{
|
|
if (!EnsureMutable(aNewLen)) {
|
|
*aData = nullptr;
|
|
return 0;
|
|
}
|
|
|
|
*aData = mData;
|
|
return mLength;
|
|
}
|
|
|
|
#if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER)
|
|
size_type GetMutableData(wchar_t** aData, size_type aNewLen = size_type(-1))
|
|
{
|
|
return GetMutableData(reinterpret_cast<char16_t**>(aData), aNewLen);
|
|
}
|
|
|
|
size_type GetMutableData(wchar_t** aData, size_type aNewLen, const fallible_t&)
|
|
{
|
|
return GetMutableData(reinterpret_cast<char16_t**>(aData), aNewLen,
|
|
fallible_t());
|
|
}
|
|
#endif
|
|
|
|
|
|
/**
|
|
* string data is never null, but can be marked void. if true, the
|
|
* string will be truncated. @see nsTSubstring::IsVoid
|
|
*/
|
|
|
|
void NS_FASTCALL SetIsVoid(bool);
|
|
|
|
/**
|
|
* This method is used to remove all occurrences of aChar from this
|
|
* string.
|
|
*
|
|
* @param aChar -- char to be stripped
|
|
* @param aOffset -- where in this string to start stripping chars
|
|
*/
|
|
|
|
void StripChar(char_type aChar, int32_t aOffset = 0);
|
|
|
|
/**
|
|
* This method is used to remove all occurrences of aChars from this
|
|
* string.
|
|
*
|
|
* @param aChars -- chars to be stripped
|
|
* @param aOffset -- where in this string to start stripping chars
|
|
*/
|
|
|
|
void StripChars(const char_type* aChars, uint32_t aOffset = 0);
|
|
|
|
/**
|
|
* If the string uses a shared buffer, this method
|
|
* clears the pointer without releasing the buffer.
|
|
*/
|
|
void ForgetSharedBuffer()
|
|
{
|
|
if (mFlags & nsSubstring::F_SHARED) {
|
|
mData = char_traits::sEmptyBuffer;
|
|
mLength = 0;
|
|
mFlags = F_TERMINATED;
|
|
}
|
|
}
|
|
|
|
public:
|
|
|
|
/**
|
|
* this is public to support automatic conversion of tuple to string
|
|
* base type, which helps avoid converting to nsTAString.
|
|
*/
|
|
MOZ_IMPLICIT nsTSubstring_CharT(const substring_tuple_type& aTuple)
|
|
: mData(nullptr)
|
|
, mLength(0)
|
|
, mFlags(F_NONE)
|
|
{
|
|
Assign(aTuple);
|
|
}
|
|
|
|
/**
|
|
* allows for direct initialization of a nsTSubstring object.
|
|
*
|
|
* NOTE: this constructor is declared public _only_ for convenience
|
|
* inside the string implementation.
|
|
*/
|
|
// XXXbz or can I just include nscore.h and use NS_BUILD_REFCNT_LOGGING?
|
|
#if defined(DEBUG) || defined(FORCE_BUILD_REFCNT_LOGGING)
|
|
#define XPCOM_STRING_CONSTRUCTOR_OUT_OF_LINE
|
|
nsTSubstring_CharT(char_type* aData, size_type aLength, uint32_t aFlags);
|
|
#else
|
|
#undef XPCOM_STRING_CONSTRUCTOR_OUT_OF_LINE
|
|
nsTSubstring_CharT(char_type* aData, size_type aLength, uint32_t aFlags)
|
|
: mData(aData)
|
|
, mLength(aLength)
|
|
, mFlags(aFlags)
|
|
{
|
|
}
|
|
#endif /* DEBUG || FORCE_BUILD_REFCNT_LOGGING */
|
|
|
|
size_t SizeOfExcludingThisMustBeUnshared(mozilla::MallocSizeOf aMallocSizeOf)
|
|
const;
|
|
size_t SizeOfIncludingThisMustBeUnshared(mozilla::MallocSizeOf aMallocSizeOf)
|
|
const;
|
|
|
|
size_t SizeOfExcludingThisIfUnshared(mozilla::MallocSizeOf aMallocSizeOf)
|
|
const;
|
|
size_t SizeOfIncludingThisIfUnshared(mozilla::MallocSizeOf aMallocSizeOf)
|
|
const;
|
|
|
|
/**
|
|
* WARNING: Only use these functions if you really know what you are
|
|
* doing, because they can easily lead to double-counting strings. If
|
|
* you do use them, please explain clearly in a comment why it's safe
|
|
* and won't lead to double-counting.
|
|
*/
|
|
size_t SizeOfExcludingThisEvenIfShared(mozilla::MallocSizeOf aMallocSizeOf)
|
|
const;
|
|
size_t SizeOfIncludingThisEvenIfShared(mozilla::MallocSizeOf aMallocSizeOf)
|
|
const;
|
|
|
|
protected:
|
|
|
|
friend class nsTObsoleteAStringThunk_CharT;
|
|
friend class nsTSubstringTuple_CharT;
|
|
|
|
// XXX GCC 3.4 needs this :-(
|
|
friend class nsTPromiseFlatString_CharT;
|
|
|
|
char_type* mData;
|
|
size_type mLength;
|
|
uint32_t mFlags;
|
|
|
|
// default initialization
|
|
nsTSubstring_CharT()
|
|
: mData(char_traits::sEmptyBuffer)
|
|
, mLength(0)
|
|
, mFlags(F_TERMINATED)
|
|
{
|
|
}
|
|
|
|
// version of constructor that leaves mData and mLength uninitialized
|
|
explicit
|
|
nsTSubstring_CharT(uint32_t aFlags)
|
|
: mFlags(aFlags)
|
|
{
|
|
}
|
|
|
|
// copy-constructor, constructs as dependent on given object
|
|
// (NOTE: this is for internal use only)
|
|
nsTSubstring_CharT(const self_type& aStr)
|
|
: mData(aStr.mData)
|
|
, mLength(aStr.mLength)
|
|
, mFlags(aStr.mFlags & (F_TERMINATED | F_VOIDED))
|
|
{
|
|
}
|
|
|
|
/**
|
|
* this function releases mData and does not change the value of
|
|
* any of its member variables. in other words, this function acts
|
|
* like a destructor.
|
|
*/
|
|
void NS_FASTCALL Finalize();
|
|
|
|
/**
|
|
* this function prepares mData to be mutated.
|
|
*
|
|
* @param aCapacity specifies the required capacity of mData
|
|
* @param aOldData returns null or the old value of mData
|
|
* @param aOldFlags returns 0 or the old value of mFlags
|
|
*
|
|
* if mData is already mutable and of sufficient capacity, then this
|
|
* function will return immediately. otherwise, it will either resize
|
|
* mData or allocate a new shared buffer. if it needs to allocate a
|
|
* new buffer, then it will return the old buffer and the corresponding
|
|
* flags. this allows the caller to decide when to free the old data.
|
|
*
|
|
* this function returns false if is unable to allocate sufficient
|
|
* memory.
|
|
*
|
|
* XXX we should expose a way for subclasses to free old_data.
|
|
*/
|
|
bool NS_FASTCALL MutatePrep(size_type aCapacity,
|
|
char_type** aOldData, uint32_t* aOldFlags);
|
|
|
|
/**
|
|
* this function prepares a section of mData to be modified. if
|
|
* necessary, this function will reallocate mData and possibly move
|
|
* existing data to open up the specified section.
|
|
*
|
|
* @param aCutStart specifies the starting offset of the section
|
|
* @param aCutLength specifies the length of the section to be replaced
|
|
* @param aNewLength specifies the length of the new section
|
|
*
|
|
* for example, suppose mData contains the string "abcdef" then
|
|
*
|
|
* ReplacePrep(2, 3, 4);
|
|
*
|
|
* would cause mData to look like "ab____f" where the characters
|
|
* indicated by '_' have an unspecified value and can be freely
|
|
* modified. this function will null-terminate mData upon return.
|
|
*
|
|
* this function returns false if is unable to allocate sufficient
|
|
* memory.
|
|
*/
|
|
NS_WARN_UNUSED_RESULT bool ReplacePrep(index_type aCutStart,
|
|
size_type aCutLength,
|
|
size_type aNewLength)
|
|
{
|
|
aCutLength = XPCOM_MIN(aCutLength, mLength - aCutStart);
|
|
uint32_t newTotalLen = mLength - aCutLength + aNewLength;
|
|
if (aCutStart == mLength && Capacity() > newTotalLen) {
|
|
mFlags &= ~F_VOIDED;
|
|
mData[newTotalLen] = char_type(0);
|
|
mLength = newTotalLen;
|
|
return true;
|
|
}
|
|
return ReplacePrepInternal(aCutStart, aCutLength, aNewLength, newTotalLen);
|
|
}
|
|
|
|
NS_WARN_UNUSED_RESULT bool NS_FASTCALL ReplacePrepInternal(
|
|
index_type aCutStart,
|
|
size_type aCutLength,
|
|
size_type aNewFragLength,
|
|
size_type aNewTotalLength);
|
|
|
|
/**
|
|
* returns the number of writable storage units starting at mData.
|
|
* the value does not include space for the null-terminator character.
|
|
*
|
|
* NOTE: this function returns 0 if mData is immutable (or the buffer
|
|
* is 0-sized).
|
|
*/
|
|
size_type NS_FASTCALL Capacity() const;
|
|
|
|
/**
|
|
* this helper function can be called prior to directly manipulating
|
|
* the contents of mData. see, for example, BeginWriting.
|
|
*/
|
|
NS_WARN_UNUSED_RESULT bool NS_FASTCALL EnsureMutable(
|
|
size_type aNewLen = size_type(-1));
|
|
|
|
/**
|
|
* returns true if this string overlaps with the given string fragment.
|
|
*/
|
|
bool IsDependentOn(const char_type* aStart, const char_type* aEnd) const
|
|
{
|
|
/**
|
|
* if it _isn't_ the case that one fragment starts after the other ends,
|
|
* or ends before the other starts, then, they conflict:
|
|
*
|
|
* !(f2.begin >= f1.aEnd || f2.aEnd <= f1.begin)
|
|
*
|
|
* Simplified, that gives us:
|
|
*/
|
|
return (aStart < (mData + mLength) && aEnd > mData);
|
|
}
|
|
|
|
/**
|
|
* this helper function stores the specified dataFlags in mFlags
|
|
*/
|
|
void SetDataFlags(uint32_t aDataFlags)
|
|
{
|
|
NS_ASSERTION((aDataFlags & 0xFFFF0000) == 0, "bad flags");
|
|
mFlags = aDataFlags | (mFlags & 0xFFFF0000);
|
|
}
|
|
|
|
void NS_FASTCALL ReplaceLiteral(index_type aCutStart, size_type aCutLength,
|
|
const char_type* aData, size_type aLength);
|
|
|
|
static int AppendFunc(void* aArg, const char* aStr, uint32_t aLen);
|
|
|
|
public:
|
|
|
|
// NOTE: this method is declared public _only_ for convenience for
|
|
// callers who don't have access to the original nsLiteralString_CharT.
|
|
void NS_FASTCALL AssignLiteral(const char_type* aData, size_type aLength);
|
|
|
|
// mFlags is a bitwise combination of the following flags. the meaning
|
|
// and interpretation of these flags is an implementation detail.
|
|
//
|
|
// NOTE: these flags are declared public _only_ for convenience inside
|
|
// the string implementation.
|
|
|
|
enum
|
|
{
|
|
F_NONE = 0, // no flags
|
|
|
|
// data flags are in the lower 16-bits
|
|
F_TERMINATED = 1 << 0, // IsTerminated returns true
|
|
F_VOIDED = 1 << 1, // IsVoid returns true
|
|
F_SHARED = 1 << 2, // mData points to a heap-allocated, shared buffer
|
|
F_OWNED = 1 << 3, // mData points to a heap-allocated, raw buffer
|
|
F_FIXED = 1 << 4, // mData points to a fixed-size writable, dependent buffer
|
|
F_LITERAL = 1 << 5, // mData points to a string literal; F_TERMINATED will also be set
|
|
|
|
// class flags are in the upper 16-bits
|
|
F_CLASS_FIXED = 1 << 16 // indicates that |this| is of type nsTFixedString
|
|
};
|
|
|
|
//
|
|
// Some terminology:
|
|
//
|
|
// "dependent buffer" A dependent buffer is one that the string class
|
|
// does not own. The string class relies on some
|
|
// external code to ensure the lifetime of the
|
|
// dependent buffer.
|
|
//
|
|
// "shared buffer" A shared buffer is one that the string class
|
|
// allocates. When it allocates a shared string
|
|
// buffer, it allocates some additional space at
|
|
// the beginning of the buffer for additional
|
|
// fields, including a reference count and a
|
|
// buffer length. See nsStringHeader.
|
|
//
|
|
// "adopted buffer" An adopted buffer is a raw string buffer
|
|
// allocated on the heap (using nsMemory::Alloc)
|
|
// of which the string class subsumes ownership.
|
|
//
|
|
// Some comments about the string flags:
|
|
//
|
|
// F_SHARED, F_OWNED, and F_FIXED are all mutually exlusive. They
|
|
// indicate the allocation type of mData. If none of these flags
|
|
// are set, then the string buffer is dependent.
|
|
//
|
|
// F_SHARED, F_OWNED, or F_FIXED imply F_TERMINATED. This is because
|
|
// the string classes always allocate null-terminated buffers, and
|
|
// non-terminated substrings are always dependent.
|
|
//
|
|
// F_VOIDED implies F_TERMINATED, and moreover it implies that mData
|
|
// points to char_traits::sEmptyBuffer. Therefore, F_VOIDED is
|
|
// mutually exclusive with F_SHARED, F_OWNED, and F_FIXED.
|
|
//
|
|
};
|
|
|
|
int NS_FASTCALL
|
|
Compare(const nsTSubstring_CharT::base_string_type& aLhs,
|
|
const nsTSubstring_CharT::base_string_type& aRhs,
|
|
const nsTStringComparator_CharT& = nsTDefaultStringComparator_CharT());
|
|
|
|
|
|
inline bool
|
|
operator!=(const nsTSubstring_CharT::base_string_type& aLhs,
|
|
const nsTSubstring_CharT::base_string_type& aRhs)
|
|
{
|
|
return !aLhs.Equals(aRhs);
|
|
}
|
|
|
|
inline bool
|
|
operator<(const nsTSubstring_CharT::base_string_type& aLhs,
|
|
const nsTSubstring_CharT::base_string_type& aRhs)
|
|
{
|
|
return Compare(aLhs, aRhs) < 0;
|
|
}
|
|
|
|
inline bool
|
|
operator<=(const nsTSubstring_CharT::base_string_type& aLhs,
|
|
const nsTSubstring_CharT::base_string_type& aRhs)
|
|
{
|
|
return Compare(aLhs, aRhs) <= 0;
|
|
}
|
|
|
|
inline bool
|
|
operator==(const nsTSubstring_CharT::base_string_type& aLhs,
|
|
const nsTSubstring_CharT::base_string_type& aRhs)
|
|
{
|
|
return aLhs.Equals(aRhs);
|
|
}
|
|
|
|
inline bool
|
|
operator==(const nsTSubstring_CharT::base_string_type& aLhs,
|
|
const nsTSubstring_CharT::char_type* aRhs)
|
|
{
|
|
return aLhs.Equals(aRhs);
|
|
}
|
|
|
|
|
|
inline bool
|
|
operator>=(const nsTSubstring_CharT::base_string_type& aLhs,
|
|
const nsTSubstring_CharT::base_string_type& aRhs)
|
|
{
|
|
return Compare(aLhs, aRhs) >= 0;
|
|
}
|
|
|
|
inline bool
|
|
operator>(const nsTSubstring_CharT::base_string_type& aLhs,
|
|
const nsTSubstring_CharT::base_string_type& aRhs)
|
|
{
|
|
return Compare(aLhs, aRhs) > 0;
|
|
}
|