diff --git a/build/valgrind/cross-architecture.sup b/build/valgrind/cross-architecture.sup index 63f4db176127..c81e6558ed0b 100644 --- a/build/valgrind/cross-architecture.sup +++ b/build/valgrind/cross-architecture.sup @@ -15,7 +15,7 @@ PR_SetEnv requires its argument to be leaked, but does not appear on stacks. (See bug 793549.) Memcheck:Leak ... - fun:_ZL13SaveWordToEnvPKcRK10nsACString + fun:_ZL13SaveWordToEnvPKcRK12nsTSubstringIcE ... } { diff --git a/js/src/devtools/rootAnalysis/analyzeHeapWrites.js b/js/src/devtools/rootAnalysis/analyzeHeapWrites.js index 75dbb07e8e5f..669cb124d61a 100644 --- a/js/src/devtools/rootAnalysis/analyzeHeapWrites.js +++ b/js/src/devtools/rootAnalysis/analyzeHeapWrites.js @@ -445,17 +445,17 @@ function ignoreContents(entry) /nsTArray_base.*?::EnsureCapacity/, /nsTArray_base.*?::ShiftData/, /AutoTArray.*?::Init/, - /nsAC?String::SetCapacity/, - /nsAC?String::SetLength/, - /nsAC?String::Assign/, - /nsAC?String::Append/, - /nsAC?String::Replace/, - /nsAC?String::Trim/, - /nsAC?String::Truncate/, - /nsAString::StripTaggedASCII/, - /nsAC?String::operator=/, - /nsAutoString::nsAutoString/, - /nsFixedCString::nsFixedCString/, + /nsTSubstring::SetCapacity/, + /nsTSubstring::SetLength/, + /nsTSubstring::Assign/, + /nsTSubstring::Append/, + /nsTSubstring::Replace/, + /nsTSubstring::Trim/, + /nsTSubstring::Truncate/, + /nsTSubstring::StripTaggedASCII/, + /nsTSubstring::operator=/, + /nsTAutoStringN::nsTAutoStringN/, + /nsTFixedString::nsTFixedString/, // Similar for some other data structures /nsCOMArray_base::SetCapacity/, diff --git a/layout/style/ServoBindings.toml b/layout/style/ServoBindings.toml index d04e851b789b..d2f7a4b2f3cc 100644 --- a/layout/style/ServoBindings.toml +++ b/layout/style/ServoBindings.toml @@ -343,7 +343,8 @@ mapped-generic-types = [ { generic = false, gecko = "ServoStyleContextStrong", servo = "::gecko_bindings::sugar::ownership::Strong<::properties::ComputedValues>" }, ] fixups = [ - { pat = "root::nsString", rep = "::nsstring::nsStringRepr" }, + { pat = "\\broot::nsString\\b", rep = "::nsstring::nsStringRepr" }, + { pat = "\\broot::nsTString", rep = "::nsstring::nsStringRepr" }, ] [bindings] @@ -541,6 +542,8 @@ servo-borrow-types = [ "RawGeckoStyleChildrenIterator", ] fixups = [ + # Remap the templated string type to the helper type + { pat = "\\bnsTString", rep = "nsString" }, # hack for gecko-owned string - { pat = " nsString::char_type(0), static_assert(sizeof(nsCString::char_type) == 1, "size of nsCString::char_type must be 1"); +static_assert(sizeof(nsTLiteralString) == sizeof(nsTString), + "nsLiteralCString can masquerade as nsCString, " + "so they must have identical layout"); + +static_assert(sizeof(nsTLiteralString) == sizeof(nsTString), + "nsTLiteralString can masquerade as nsString, " + "so they must have identical layout"); + /** * A helper class that converts a UTF-16 string to ASCII in a lossy manner @@ -60,7 +61,7 @@ public: NS_LossyConvertUTF16toASCII(const char16ptr_t aString, uint32_t aLength) { - LossyAppendUTF16toASCII(Substring(aString, aLength), *this); + LossyAppendUTF16toASCII(Substring(static_cast(aString), aLength), *this); } explicit NS_LossyConvertUTF16toASCII(const nsAString& aString) @@ -111,7 +112,7 @@ public: NS_ConvertUTF16toUTF8(const char16ptr_t aString, uint32_t aLength) { - AppendUTF16toUTF8(Substring(aString, aLength), *this); + AppendUTF16toUTF8(Substring(static_cast(aString), aLength), *this); } explicit NS_ConvertUTF16toUTF8(const nsAString& aString) diff --git a/xpcom/string/nsStringComparator.cpp b/xpcom/string/nsStringComparator.cpp index 81f1629f8538..b81a84d3da84 100644 --- a/xpcom/string/nsStringComparator.cpp +++ b/xpcom/string/nsStringComparator.cpp @@ -8,16 +8,7 @@ #include "nsAString.h" #include "plstr.h" - -// define nsStringComparator -#include "string-template-def-unichar.h" #include "nsTStringComparator.cpp" -#include "string-template-undef.h" - -// define nsCStringComparator -#include "string-template-def-char.h" -#include "nsTStringComparator.cpp" -#include "string-template-undef.h" int diff --git a/xpcom/string/nsStringFlags.h b/xpcom/string/nsStringFlags.h new file mode 100644 index 000000000000..d71f4a8581ec --- /dev/null +++ b/xpcom/string/nsStringFlags.h @@ -0,0 +1,76 @@ +/* -*- 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/. */ + +#ifndef nsStringFlags_h +#define nsStringFlags_h + +#include +#include "mozilla/TypedEnumBits.h" + +namespace mozilla { +namespace detail { +// NOTE: these flags are declared public _only_ for convenience inside +// the string implementation. And they are outside of the string +// class so that the type is the same for both narrow and wide +// strings. + +// bits for mDataFlags +enum class StringDataFlags : uint16_t +{ + // 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 moz_xmalloc) + // of which the string class subsumes ownership. + // + // Some comments about the string data flags: + // + // SHARED, OWNED, and 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. + // + // SHARED, OWNED, or FIXED imply TERMINATED. This is because + // the string classes always allocate null-terminated buffers, and + // non-terminated substrings are always dependent. + // + // VOIDED implies TERMINATED, and moreover it implies that mData + // points to char_traits::sEmptyBuffer. Therefore, VOIDED is + // mutually exclusive with SHARED, OWNED, and FIXED. + + TERMINATED = 1 << 0, // IsTerminated returns true + VOIDED = 1 << 1, // IsVoid returns true + SHARED = 1 << 2, // mData points to a heap-allocated, shared buffer + OWNED = 1 << 3, // mData points to a heap-allocated, raw buffer + FIXED = 1 << 4, // mData points to a fixed-size writable, dependent buffer + LITERAL = 1 << 5 // mData points to a string literal; DataFlags::TERMINATED will also be set +}; + +// bits for mClassFlags +enum class StringClassFlags : uint16_t +{ + FIXED = 1 << 0, // |this| is of type nsTFixedString + NULL_TERMINATED = 1 << 1 // |this| requires its buffer is null-terminated +}; + +MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(StringDataFlags) +MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(StringClassFlags) + +} // namespace detail +} // namespace mozilla + +#endif diff --git a/xpcom/string/nsStringFwd.h b/xpcom/string/nsStringFwd.h index 89c7c03b4df8..6cc4f8a88f04 100644 --- a/xpcom/string/nsStringFwd.h +++ b/xpcom/string/nsStringFwd.h @@ -14,36 +14,62 @@ namespace mozilla { namespace detail { -class nsStringRepr; -class nsCStringRepr; +template class nsTStringRepr; + +using nsStringRepr = nsTStringRepr; +using nsCStringRepr = nsTStringRepr; } // namespace detail } // namespace mozilla static const size_t AutoStringDefaultStorageSize = 64; +template class nsTSubstring; +template class nsTSubstringTuple; +template class nsTString; +template class nsTAutoStringN; +template class nsTDependentString; +template class nsTDependentSubstring; +template class nsTPromiseFlatString; +template class nsTStringComparator; +template class nsTDefaultStringComparator; +template class nsTLiteralString; +template class nsTFixedString; + +// We define this version without a size param instead of providing a +// default value for N so that so there is a default typename that doesn't +// require angle brackets. +template using nsTAutoString = nsTAutoStringN; + + // Double-byte (char16_t) string types. -class nsAString; -class nsSubstringTuple; -class nsString; -template class nsAutoStringN; -using nsAutoString = nsAutoStringN; -class nsDependentString; -class nsDependentSubstring; -class nsPromiseFlatString; -class nsStringComparator; -class nsDefaultStringComparator; + +using nsAString = nsTSubstring; +using nsSubstringTuple = nsTSubstringTuple; +using nsString = nsTString; +using nsAutoString = nsTAutoString; +template using nsAutoStringN = nsTAutoStringN; +using nsDependentString = nsTDependentString; +using nsDependentSubstring = nsTDependentSubstring; +using nsPromiseFlatString = nsTPromiseFlatString; +using nsStringComparator = nsTStringComparator; +using nsDefaultStringComparator = nsTDefaultStringComparator; +using nsLiteralString = nsTLiteralString; +using nsFixedString = nsTFixedString; // Single-byte (char) string types. -class nsACString; -class nsCSubstringTuple; -class nsCString; -template class nsAutoCStringN; -using nsAutoCString = nsAutoCStringN; -class nsDependentCString; -class nsDependentCSubstring; -class nsPromiseFlatCString; -class nsCStringComparator; -class nsDefaultCStringComparator; + +using nsACString = nsTSubstring; +using nsCSubstringTuple = nsTSubstringTuple; +using nsCString = nsTString; +using nsAutoCString = nsTAutoString; +template using nsAutoCStringN = nsTAutoStringN; +using nsDependentCString = nsTDependentString; +using nsDependentCSubstring = nsTDependentSubstring; +using nsPromiseFlatCString = nsTPromiseFlatString; +using nsCStringComparator = nsTStringComparator; +using nsDefaultCStringComparator = nsTDefaultStringComparator; +using nsLiteralCString = nsTLiteralString; +using nsFixedCString = nsTFixedString; #endif /* !defined(nsStringFwd_h) */ diff --git a/xpcom/string/nsStringIterator.h b/xpcom/string/nsStringIterator.h index 91f00fd504f2..b8a469ace8c0 100644 --- a/xpcom/string/nsStringIterator.h +++ b/xpcom/string/nsStringIterator.h @@ -27,8 +27,7 @@ public: typedef const CharT& reference; private: - friend class mozilla::detail::nsStringRepr; - friend class mozilla::detail::nsCStringRepr; + friend class mozilla::detail::nsTStringRepr; // unfortunately, the API for nsReadingIterator requires that the // iterator know its start and end positions. this was needed when @@ -130,8 +129,7 @@ public: typedef CharT& reference; private: - friend class nsAString; - friend class nsACString; + friend class nsTSubstring; // unfortunately, the API for nsWritingIterator requires that the // iterator know its start and end positions. this was needed when diff --git a/xpcom/string/nsStringObsolete.cpp b/xpcom/string/nsStringObsolete.cpp index d7a350e4a608..cb891255d66e 100644 --- a/xpcom/string/nsStringObsolete.cpp +++ b/xpcom/string/nsStringObsolete.cpp @@ -849,78 +849,86 @@ RFind_ComputeSearchRange( uint32_t bigLen, uint32_t littleLen, int32_t& offset, //----------------------------------------------------------------------------- -// define nsString obsolete methods -#include "string-template-def-unichar.h" #include "nsTStringObsolete.cpp" -#include "string-template-undef.h" - -// define nsCString obsolete methods -#include "string-template-def-char.h" -#include "nsTStringObsolete.cpp" -#include "string-template-undef.h" //----------------------------------------------------------------------------- // specialized methods: +template +template int32_t -nsString::Find( const nsString& aString, int32_t aOffset, int32_t aCount ) const +nsTString::Find(const self_type& aString, int32_t aOffset, int32_t aCount) const { // this method changes the meaning of aOffset and aCount: - Find_ComputeSearchRange(mLength, aString.Length(), aOffset, aCount); + Find_ComputeSearchRange(this->mLength, aString.Length(), aOffset, aCount); - int32_t result = FindSubstring(mData + aOffset, aCount, static_cast(aString.get()), aString.Length(), false); + // Capture the raw buffer locally to help msvc deduce the type. + const char_type* str = aString.get(); + int32_t result = FindSubstring(this->mData + aOffset, aCount, str, aString.Length(), false); if (result != kNotFound) result += aOffset; return result; } +template +template int32_t -nsString::Find( const char16_t* aString, int32_t aOffset, int32_t aCount ) const +nsTString::Find(const char_type* aString, int32_t aOffset, int32_t aCount) const { - return Find(nsDependentString(aString), aOffset, aCount); + return Find(nsTDependentString(aString), aOffset, aCount); } +template +template int32_t -nsString::RFind( const nsString& aString, int32_t aOffset, int32_t aCount ) const +nsTString::RFind(const self_type& aString, int32_t aOffset, int32_t aCount) const { // this method changes the meaning of aOffset and aCount: - RFind_ComputeSearchRange(mLength, aString.Length(), aOffset, aCount); + RFind_ComputeSearchRange(this->mLength, aString.Length(), aOffset, aCount); - int32_t result = RFindSubstring(mData + aOffset, aCount, static_cast(aString.get()), aString.Length(), false); + // Capture the raw buffer locally to help msvc deduce the type. + const char_type* str = aString.get(); + int32_t result = RFindSubstring(this->mData + aOffset, aCount, str, aString.Length(), false); if (result != kNotFound) result += aOffset; return result; } +template +template int32_t -nsString::RFind( const char16_t* aString, int32_t aOffset, int32_t aCount ) const +nsTString::RFind(const char_type* aString, int32_t aOffset, int32_t aCount) const { - return RFind(nsDependentString(aString), aOffset, aCount); + return RFind(nsTDependentString(aString), aOffset, aCount); } +template +template int32_t -nsString::FindCharInSet( const char16_t* aSet, int32_t aOffset ) const +nsTString::FindCharInSet(const char* aSet, int32_t aOffset) const { if (aOffset < 0) aOffset = 0; - else if (aOffset >= int32_t(mLength)) + else if (aOffset >= int32_t(this->mLength)) return kNotFound; - int32_t result = ::FindCharInSet(mData + aOffset, mLength - aOffset, aSet); + int32_t result = ::FindCharInSet(this->mData + aOffset, this->mLength - aOffset, aSet); if (result != kNotFound) result += aOffset; return result; } +template +template void -nsString::ReplaceChar( const char16_t* aSet, char16_t aNewChar ) +nsTString::ReplaceChar(const char* aSet, char16_t aNewChar) { - if (!EnsureMutable()) // XXX do this lazily? - AllocFailed(mLength); + if (!this->EnsureMutable()) // XXX do this lazily? + this->AllocFailed(this->mLength); - char16_t* data = mData; - uint32_t lenRemaining = mLength; + char16_t* data = this->mData; + uint32_t lenRemaining = this->mLength; while (lenRemaining) { @@ -939,12 +947,14 @@ nsString::ReplaceChar( const char16_t* aSet, char16_t aNewChar ) * nsTString::Compare,CompareWithConversion,etc. */ +template +template int32_t -nsCString::Compare( const char* aString, bool aIgnoreCase, int32_t aCount ) const +nsTString::Compare(const char_type* aString, bool aIgnoreCase, int32_t aCount) const { uint32_t strLen = char_traits::length(aString); - int32_t maxCount = int32_t(XPCOM_MIN(mLength, strLen)); + int32_t maxCount = int32_t(XPCOM_MIN(this->mLength, strLen)); int32_t compareCount; if (aCount < 0 || aCount > maxCount) @@ -953,27 +963,29 @@ nsCString::Compare( const char* aString, bool aIgnoreCase, int32_t aCount ) cons compareCount = aCount; int32_t result = - nsBufferRoutines::compare(mData, aString, compareCount, aIgnoreCase); + nsBufferRoutines::compare(this->mData, aString, compareCount, aIgnoreCase); if (result == 0 && - (aCount < 0 || strLen < uint32_t(aCount) || mLength < uint32_t(aCount))) + (aCount < 0 || strLen < uint32_t(aCount) || this->mLength < uint32_t(aCount))) { // Since the caller didn't give us a length to test, or strings shorter // than aCount, and compareCount characters matched, we have to assume // that the longer string is greater. - if (mLength != strLen) - result = (mLength < strLen) ? -1 : 1; + if (this->mLength != strLen) + result = (this->mLength < strLen) ? -1 : 1; } return result; } +template +template bool -nsString::EqualsIgnoreCase( const char* aString, int32_t aCount ) const +nsTString::EqualsIgnoreCase(const incompatible_char_type* aString, int32_t aCount) const { uint32_t strLen = nsCharTraits::length(aString); - int32_t maxCount = int32_t(XPCOM_MIN(mLength, strLen)); + int32_t maxCount = int32_t(XPCOM_MIN(this->mLength, strLen)); int32_t compareCount; if (aCount < 0 || aCount > maxCount) @@ -982,16 +994,16 @@ nsString::EqualsIgnoreCase( const char* aString, int32_t aCount ) const compareCount = aCount; int32_t result = - nsBufferRoutines::compare(mData, aString, compareCount, true); + nsBufferRoutines::compare(this->mData, aString, compareCount, true); if (result == 0 && - (aCount < 0 || strLen < uint32_t(aCount) || mLength < uint32_t(aCount))) + (aCount < 0 || strLen < uint32_t(aCount) || this->mLength < uint32_t(aCount))) { // Since the caller didn't give us a length to test, or strings shorter // than aCount, and compareCount characters matched, we have to assume // that the longer string is greater. - if (mLength != strLen) + if (this->mLength != strLen) result = 1; // Arbitrarily using any number != 0 } return result == 0; @@ -1002,17 +1014,18 @@ nsString::EqualsIgnoreCase( const char* aString, int32_t aCount ) const * nsTString::ToDouble */ +template <> double -nsCString::ToDouble(nsresult* aErrorCode) const +nsTString::ToDouble(nsresult* aErrorCode) const { double res = 0.0; - if (mLength > 0) + if (this->mLength > 0) { char *conv_stopped; - const char *str = mData; + const char *str = this->mData; // Use PR_strtod, not strtod, since we don't want locale involved. res = PR_strtod(str, &conv_stopped); - if (conv_stopped == str+mLength) + if (conv_stopped == str+this->mLength) *aErrorCode = NS_OK; else // Not all the string was scanned *aErrorCode = NS_ERROR_ILLEGAL_VALUE; @@ -1025,10 +1038,21 @@ nsCString::ToDouble(nsresult* aErrorCode) const return res; } +template <> double -nsString::ToDouble(nsresult* aErrorCode) const +nsTString::ToDouble(nsresult* aErrorCode) const { return NS_LossyConvertUTF16toASCII(*this).ToDouble(aErrorCode); } +template +float +nsTString::ToFloat(nsresult* aErrorCode) const +{ + return (float)ToDouble(aErrorCode); +} + +template class nsTString; +template class nsTString; + #endif // !MOZ_STRING_WITH_OBSOLETE_API diff --git a/xpcom/string/nsSubstring.cpp b/xpcom/string/nsSubstring.cpp index 04c7350b8bc6..10636743ab9e 100644 --- a/xpcom/string/nsSubstring.cpp +++ b/xpcom/string/nsSubstring.cpp @@ -352,14 +352,7 @@ nsStringBuffer::SizeOfIncludingThisEvenIfShared(mozilla::MallocSizeOf aMallocSiz // --------------------------------------------------------------------------- // define nsAString -#include "string-template-def-unichar.h" #include "nsTSubstring.cpp" -#include "string-template-undef.h" - -// define nsACString -#include "string-template-def-char.h" -#include "nsTSubstring.cpp" -#include "string-template-undef.h" // Provide rust bindings to the nsA[C]String types extern "C" { diff --git a/xpcom/string/nsSubstringTuple.cpp b/xpcom/string/nsSubstringTuple.cpp index 1becf9ce8925..3d77967cefdb 100644 --- a/xpcom/string/nsSubstringTuple.cpp +++ b/xpcom/string/nsSubstringTuple.cpp @@ -6,12 +6,4 @@ #include "nsSubstringTuple.h" -// define nsSubstringTuple -#include "string-template-def-unichar.h" #include "nsTSubstringTuple.cpp" -#include "string-template-undef.h" - -// define nsCSubstringTuple -#include "string-template-def-char.h" -#include "nsTSubstringTuple.cpp" -#include "string-template-undef.h" diff --git a/xpcom/string/nsSubstringTuple.h b/xpcom/string/nsSubstringTuple.h index 5a61cd831855..b7e717268476 100644 --- a/xpcom/string/nsSubstringTuple.h +++ b/xpcom/string/nsSubstringTuple.h @@ -9,14 +9,6 @@ #include "nsSubstring.h" -// declare nsSubstringTuple -#include "string-template-def-unichar.h" #include "nsTSubstringTuple.h" -#include "string-template-undef.h" - -// declare nsCSubstringTuple -#include "string-template-def-char.h" -#include "nsTSubstringTuple.h" -#include "string-template-undef.h" #endif // !defined(nsSubstringTuple_h___) diff --git a/xpcom/string/nsTDependentString.cpp b/xpcom/string/nsTDependentString.cpp index 646383a52182..d54851c44e1b 100644 --- a/xpcom/string/nsTDependentString.cpp +++ b/xpcom/string/nsTDependentString.cpp @@ -4,22 +4,24 @@ * 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/. */ -nsTDependentString_CharT::nsTDependentString_CharT(const char_type* aStart, - const char_type* aEnd) +template +nsTDependentString::nsTDependentString(const char_type* aStart, + const char_type* aEnd) : string_type(const_cast(aStart), uint32_t(aEnd - aStart), DataFlags::TERMINATED, ClassFlags(0)) { MOZ_RELEASE_ASSERT(aStart <= aEnd, "Overflow!"); - AssertValidDependentString(); + this->AssertValidDependentString(); } +template void -nsTDependentString_CharT::Rebind(const string_type& str, uint32_t startPos) +nsTDependentString::Rebind(const string_type& str, uint32_t startPos) { MOZ_ASSERT(str.GetDataFlags() & DataFlags::TERMINATED, "Unterminated flat string"); // If we currently own a buffer, release it. - Finalize(); + this->Finalize(); size_type strLength = str.Length(); @@ -31,12 +33,13 @@ nsTDependentString_CharT::Rebind(const string_type& str, uint32_t startPos) const_cast(static_cast(str.Data())) + startPos; size_type newLen = strLength - startPos; DataFlags newDataFlags = str.GetDataFlags() & (DataFlags::TERMINATED | DataFlags::LITERAL); - SetData(newData, newLen, newDataFlags); + this->SetData(newData, newLen, newDataFlags); } +template void -nsTDependentString_CharT::Rebind(const char_type* aStart, const char_type* aEnd) +nsTDependentString::Rebind(const char_type* aStart, const char_type* aEnd) { MOZ_RELEASE_ASSERT(aStart <= aEnd, "Overflow!"); - Rebind(aStart, uint32_t(aEnd - aStart)); + this->Rebind(aStart, uint32_t(aEnd - aStart)); } diff --git a/xpcom/string/nsTDependentString.h b/xpcom/string/nsTDependentString.h index 9fbb79af092e..6621645866c4 100644 --- a/xpcom/string/nsTDependentString.h +++ b/xpcom/string/nsTDependentString.h @@ -4,9 +4,13 @@ * 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/. */ +#ifndef nsTDependentString_h +#define nsTDependentString_h + +#include "nsTString.h" /** - * nsTDependentString_CharT + * nsTDependentString * * Stores a null-terminated, immutable sequence of characters. * @@ -16,11 +20,41 @@ * nsTDependentString continues to reference valid memory for the * duration of its use. */ -class nsTDependentString_CharT : public nsTString_CharT +template +class nsTDependentString : public nsTString { public: - typedef nsTDependentString_CharT self_type; + typedef nsTDependentString self_type; + typedef nsTString base_string_type; + typedef typename base_string_type::string_type string_type; + + typedef typename base_string_type::fallible_t fallible_t; + + typedef typename base_string_type::char_type char_type; + typedef typename base_string_type::char_traits char_traits; + typedef typename base_string_type::incompatible_char_type incompatible_char_type; + + typedef typename base_string_type::substring_tuple_type substring_tuple_type; + + typedef typename base_string_type::const_iterator const_iterator; + typedef typename base_string_type::iterator iterator; + + typedef typename base_string_type::comparator_type comparator_type; + + typedef typename base_string_type::char_iterator char_iterator; + typedef typename base_string_type::const_char_iterator const_char_iterator; + + typedef typename base_string_type::index_type index_type; + typedef typename base_string_type::size_type size_type; + + // These are only for internal use within the string classes: + typedef typename base_string_type::DataFlags DataFlags; + typedef typename base_string_type::ClassFlags ClassFlags; + + using typename base_string_type::IsChar; + using typename base_string_type::IsChar16; + public: @@ -28,47 +62,49 @@ public: * constructors */ - nsTDependentString_CharT(const char_type* aStart, const char_type* aEnd); + nsTDependentString(const char_type* aStart, const char_type* aEnd); - nsTDependentString_CharT(const char_type* aData, uint32_t aLength) + nsTDependentString(const char_type* aData, uint32_t aLength) : string_type(const_cast(aData), aLength, DataFlags::TERMINATED, ClassFlags(0)) { - AssertValidDependentString(); + this->AssertValidDependentString(); } -#if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER) - nsTDependentString_CharT(char16ptr_t aData, uint32_t aLength) - : nsTDependentString_CharT(static_cast(aData), aLength) +#if defined(MOZ_USE_CHAR16_WRAPPER) + template + nsTDependentString(char16ptr_t aData, uint32_t aLength) + : nsTDependentString(static_cast(aData), aLength) { } #endif explicit - nsTDependentString_CharT(const char_type* aData) + nsTDependentString(const char_type* aData) : string_type(const_cast(aData), uint32_t(char_traits::length(aData)), DataFlags::TERMINATED, ClassFlags(0)) { - AssertValidDependentString(); + string_type::AssertValidDependentString(); } -#if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER) +#if defined(MOZ_USE_CHAR16_WRAPPER) + template explicit - nsTDependentString_CharT(char16ptr_t aData) - : nsTDependentString_CharT(static_cast(aData)) + nsTDependentString(char16ptr_t aData) + : nsTDependentString(static_cast(aData)) { } #endif - nsTDependentString_CharT(const string_type& aStr, uint32_t aStartPos) + nsTDependentString(const string_type& aStr, uint32_t aStartPos) : string_type() { Rebind(aStr, aStartPos); } // Create a nsTDependentSubstring to be bound later - nsTDependentString_CharT() + nsTDependentString() : string_type() { } @@ -83,7 +119,7 @@ public: * allow this class to be bound to a different string... */ - using nsTString_CharT::Rebind; + using nsTString::Rebind; void Rebind(const char_type* aData) { Rebind(aData, uint32_t(char_traits::length(aData))); @@ -95,5 +131,10 @@ public: private: // NOT USED - nsTDependentString_CharT(const substring_tuple_type&) = delete; + nsTDependentString(const substring_tuple_type&) = delete; }; + +extern template class nsTDependentString; +extern template class nsTDependentString; + +#endif diff --git a/xpcom/string/nsTDependentSubstring.cpp b/xpcom/string/nsTDependentSubstring.cpp index c287249f4f81..70052af7761a 100644 --- a/xpcom/string/nsTDependentSubstring.cpp +++ b/xpcom/string/nsTDependentSubstring.cpp @@ -4,12 +4,13 @@ * 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/. */ +template void -nsTDependentSubstring_CharT::Rebind(const substring_type& str, +nsTDependentSubstring::Rebind(const substring_type& str, uint32_t startPos, uint32_t length) { // If we currently own a buffer, release it. - Finalize(); + this->Finalize(); size_type strLength = str.Length(); @@ -21,44 +22,49 @@ nsTDependentSubstring_CharT::Rebind(const substring_type& str, const_cast(static_cast(str.Data())) + startPos; size_type newLength = XPCOM_MIN(length, strLength - startPos); DataFlags newDataFlags = DataFlags(0); - SetData(newData, newLength, newDataFlags); + this->SetData(newData, newLength, newDataFlags); } +template void -nsTDependentSubstring_CharT::Rebind(const char_type* data, size_type length) +nsTDependentSubstring::Rebind(const char_type* data, size_type length) { NS_ASSERTION(data, "nsTDependentSubstring must wrap a non-NULL buffer"); // If we currently own a buffer, release it. - Finalize(); + this->Finalize(); char_type* newData = const_cast(static_cast(data)); size_type newLength = length; DataFlags newDataFlags = DataFlags(0); - SetData(newData, newLength, newDataFlags); + this->SetData(newData, newLength, newDataFlags); } +template void -nsTDependentSubstring_CharT::Rebind(const char_type* aStart, const char_type* aEnd) +nsTDependentSubstring::Rebind(const char_type* aStart, const char_type* aEnd) { MOZ_RELEASE_ASSERT(aStart <= aEnd, "Overflow!"); - Rebind(aStart, size_type(aEnd - aStart)); + this->Rebind(aStart, size_type(aEnd - aStart)); } -nsTDependentSubstring_CharT::nsTDependentSubstring_CharT(const char_type* aStart, - const char_type* aEnd) +template +nsTDependentSubstring::nsTDependentSubstring(const char_type* aStart, + const char_type* aEnd) : substring_type(const_cast(aStart), uint32_t(aEnd - aStart), DataFlags(0), ClassFlags(0)) { MOZ_RELEASE_ASSERT(aStart <= aEnd, "Overflow!"); } -#if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER) -nsTDependentSubstring_CharT::nsTDependentSubstring_CharT(char16ptr_t aStart, - char16ptr_t aEnd) - : nsTDependentSubstring_CharT(static_cast(aStart), - static_cast(aEnd)) +#if defined(MOZ_USE_CHAR16_WRAPPER) +template +template +nsTDependentSubstring::nsTDependentSubstring(char16ptr_t aStart, + char16ptr_t aEnd) + : substring_type(static_cast(aStart), + static_cast(aEnd)) { MOZ_RELEASE_ASSERT(static_cast(aStart) <= static_cast(aEnd), @@ -66,8 +72,9 @@ nsTDependentSubstring_CharT::nsTDependentSubstring_CharT(char16ptr_t aStart, } #endif -nsTDependentSubstring_CharT::nsTDependentSubstring_CharT(const const_iterator& aStart, - const const_iterator& aEnd) +template +nsTDependentSubstring::nsTDependentSubstring(const const_iterator& aStart, + const const_iterator& aEnd) : substring_type(const_cast(aStart.get()), uint32_t(aEnd.get() - aStart.get()), DataFlags(0), ClassFlags(0)) @@ -75,9 +82,25 @@ nsTDependentSubstring_CharT::nsTDependentSubstring_CharT(const const_iterator& a MOZ_RELEASE_ASSERT(aStart.get() <= aEnd.get(), "Overflow!"); } -const nsTDependentSubstring_CharT -Substring(const CharT* aStart, const CharT* aEnd) +template +const nsTDependentSubstring +Substring(const T* aStart, const T* aEnd) { MOZ_RELEASE_ASSERT(aStart <= aEnd, "Overflow!"); - return nsTDependentSubstring_CharT(aStart, aEnd); + return nsTDependentSubstring(aStart, aEnd); } + +#if defined(MOZ_USE_CHAR16_WRAPPER) +const nsTDependentSubstring +Substring(char16ptr_t aData, uint32_t aLength) +{ + return nsTDependentSubstring(aData, aLength); +} + +const nsTDependentSubstring +Substring(char16ptr_t aStart, char16ptr_t aEnd) +{ + return Substring(static_cast(aStart), + static_cast(aEnd)); +} +#endif diff --git a/xpcom/string/nsTDependentSubstring.h b/xpcom/string/nsTDependentSubstring.h index 6dfcce8f3791..b00c64809ce5 100644 --- a/xpcom/string/nsTDependentSubstring.h +++ b/xpcom/string/nsTDependentSubstring.h @@ -5,6 +5,12 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // IWYU pragma: private, include "nsString.h" +#ifndef nsTDependentSubstring_h +#define nsTDependentSubstring_h + +#include "nsTSubstring.h" +#include "nsTLiteralString.h" + /** * nsTDependentSubstring_CharT * @@ -16,11 +22,38 @@ * nsDependentSubstring for wide characters * nsDependentCSubstring for narrow characters */ -class nsTDependentSubstring_CharT : public nsTSubstring_CharT +template +class nsTDependentSubstring : public nsTSubstring { public: - typedef nsTDependentSubstring_CharT self_type; + typedef nsTDependentSubstring self_type; + typedef nsTSubstring substring_type; + typedef typename substring_type::fallible_t fallible_t; + + typedef typename substring_type::char_type char_type; + typedef typename substring_type::char_traits char_traits; + typedef typename substring_type::incompatible_char_type incompatible_char_type; + + typedef typename substring_type::substring_tuple_type substring_tuple_type; + + typedef typename substring_type::const_iterator const_iterator; + typedef typename substring_type::iterator iterator; + + typedef typename substring_type::comparator_type comparator_type; + + typedef typename substring_type::char_iterator char_iterator; + typedef typename substring_type::const_char_iterator const_char_iterator; + + typedef typename substring_type::index_type index_type; + typedef typename substring_type::size_type size_type; + + // These are only for internal use within the string classes: + typedef typename substring_type::DataFlags DataFlags; + typedef typename substring_type::ClassFlags ClassFlags; + + using typename substring_type::IsChar; + using typename substring_type::IsChar16; public: @@ -31,35 +64,37 @@ public: void Rebind(const char_type* aStart, const char_type* aEnd); - nsTDependentSubstring_CharT(const substring_type& aStr, uint32_t aStartPos, - uint32_t aLength = size_type(-1)) + nsTDependentSubstring(const substring_type& aStr, uint32_t aStartPos, + uint32_t aLength = size_type(-1)) : substring_type() { Rebind(aStr, aStartPos, aLength); } - nsTDependentSubstring_CharT(const char_type* aData, size_type aLength) + nsTDependentSubstring(const char_type* aData, size_type aLength) : substring_type(const_cast(aData), aLength, DataFlags(0), ClassFlags(0)) { } - nsTDependentSubstring_CharT(const char_type* aStart, const char_type* aEnd); + nsTDependentSubstring(const char_type* aStart, const char_type* aEnd); -#if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER) - nsTDependentSubstring_CharT(char16ptr_t aData, size_type aLength) - : nsTDependentSubstring_CharT(static_cast(aData), aLength) +#if defined(MOZ_USE_CHAR16_WRAPPER) + template + nsTDependentSubstring(char16ptr_t aData, size_type aLength) + : nsTDependentSubstring(static_cast(aData), aLength) { } - nsTDependentSubstring_CharT(char16ptr_t aStart, char16ptr_t aEnd); + template + nsTDependentSubstring(char16ptr_t aStart, char16ptr_t aEnd); #endif - nsTDependentSubstring_CharT(const const_iterator& aStart, - const const_iterator& aEnd); + nsTDependentSubstring(const const_iterator& aStart, + const const_iterator& aEnd); // Create a nsTDependentSubstring to be bound later - nsTDependentSubstring_CharT() + nsTDependentSubstring() : substring_type() { } @@ -71,37 +106,64 @@ private: void operator=(const self_type&); // we're immutable, you can't assign into a substring }; -inline const nsTDependentSubstring_CharT -Substring(const nsTSubstring_CharT& aStr, uint32_t aStartPos, +extern template class nsTDependentSubstring; +extern template class nsTDependentSubstring; + +template +inline const nsTDependentSubstring +Substring(const nsTSubstring& aStr, uint32_t aStartPos, uint32_t aLength = uint32_t(-1)) { - return nsTDependentSubstring_CharT(aStr, aStartPos, aLength); + return nsTDependentSubstring(aStr, aStartPos, aLength); } -inline const nsTDependentSubstring_CharT -Substring(const nsReadingIterator& aStart, - const nsReadingIterator& aEnd) +template +inline const nsTDependentSubstring +Substring(const nsTLiteralString& aStr, uint32_t aStartPos, + uint32_t aLength = uint32_t(-1)) { - return nsTDependentSubstring_CharT(aStart.get(), aEnd.get()); + return nsTDependentSubstring(aStr, aStartPos, aLength); } -inline const nsTDependentSubstring_CharT -Substring(const CharT* aData, uint32_t aLength) +template +inline const nsTDependentSubstring +Substring(const nsReadingIterator& aStart, + const nsReadingIterator& aEnd) { - return nsTDependentSubstring_CharT(aData, aLength); + return nsTDependentSubstring(aStart.get(), aEnd.get()); } -const nsTDependentSubstring_CharT -Substring(const CharT* aStart, const CharT* aEnd); - -inline const nsTDependentSubstring_CharT -StringHead(const nsTSubstring_CharT& aStr, uint32_t aCount) +template +inline const nsTDependentSubstring +Substring(const T* aData, uint32_t aLength) { - return nsTDependentSubstring_CharT(aStr, 0, aCount); + return nsTDependentSubstring(aData, aLength); } -inline const nsTDependentSubstring_CharT -StringTail(const nsTSubstring_CharT& aStr, uint32_t aCount) +template +const nsTDependentSubstring +Substring(const T* aStart, const T* aEnd); + +#if defined(MOZ_USE_CHAR16_WRAPPER) +inline const nsTDependentSubstring +Substring(char16ptr_t aData, uint32_t aLength); + +const nsTDependentSubstring +Substring(char16ptr_t aStart, char16ptr_t aEnd); +#endif + +template +inline const nsTDependentSubstring +StringHead(const nsTSubstring& aStr, uint32_t aCount) { - return nsTDependentSubstring_CharT(aStr, aStr.Length() - aCount, aCount); + return nsTDependentSubstring(aStr, 0, aCount); } + +template +inline const nsTDependentSubstring +StringTail(const nsTSubstring& aStr, uint32_t aCount) +{ + return nsTDependentSubstring(aStr, aStr.Length() - aCount, aCount); +} + +#endif diff --git a/xpcom/string/nsTLiteralString.h b/xpcom/string/nsTLiteralString.h index 470c5348281b..00002d1828fb 100644 --- a/xpcom/string/nsTLiteralString.h +++ b/xpcom/string/nsTLiteralString.h @@ -4,6 +4,11 @@ * 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/. */ +#ifndef nsTLiteralString_h +#define nsTLiteralString_h + +#include "nsTStringRepr.h" + /** * nsTLiteralString_CharT * @@ -15,11 +20,17 @@ * to be static (permanent) and therefore, as an optimization, this class * does not have a destructor. */ -class nsTLiteralString_CharT : public mozilla::detail::nsTStringRepr_CharT +template +class nsTLiteralString : public mozilla::detail::nsTStringRepr { public: - typedef nsTLiteralString_CharT self_type; + typedef nsTLiteralString self_type; + typedef typename mozilla::detail::nsTStringRepr::base_string_type base_string_type; + typedef typename base_string_type::char_type char_type; + typedef typename base_string_type::size_type size_type; + typedef typename base_string_type::DataFlags DataFlags; + typedef typename base_string_type::ClassFlags ClassFlags; public: @@ -28,7 +39,7 @@ public: */ template - explicit constexpr nsTLiteralString_CharT(const char_type (&aStr)[N]) + explicit constexpr nsTLiteralString(const char_type (&aStr)[N]) : base_string_type(const_cast(aStr), N - 1, DataFlags::TERMINATED | DataFlags::LITERAL, ClassFlags::NULL_TERMINATED) @@ -40,40 +51,42 @@ public: * Use sparingly. If possible, rewrite code to use const ns[C]String& * and the implicit cast will just work. */ - const nsTString_CharT& AsString() const + const nsTString& AsString() const { - return *reinterpret_cast(this); + return *reinterpret_cast*>(this); } - operator const nsTString_CharT&() const + operator const nsTString&() const { return AsString(); } + template struct raw_type { typedef N* type; }; + +#ifdef MOZ_USE_CHAR16_WRAPPER + template<> struct raw_type { typedef char16ptr_t type; }; +#endif + /** * Prohibit get() on temporaries as in nsLiteralCString("x").get(). * These should be written as just "x", using a string literal directly. */ -#if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER) - char16ptr_t get() const && = delete; - char16ptr_t get() const & -#else - const char_type* get() const && = delete; - const char_type* get() const & -#endif + const typename raw_type::type get() const && = delete; + const typename raw_type::type get() const & { - return mData; + return this->mData; } private: // NOT TO BE IMPLEMENTED template - nsTLiteralString_CharT(char_type (&aStr)[N]) = delete; + nsTLiteralString(char_type (&aStr)[N]) = delete; self_type& operator=(const self_type&) = delete; }; -static_assert(sizeof(nsTLiteralString_CharT) == sizeof(nsTString_CharT), - "nsTLiteralString_CharT can masquerade as nsTString_CharT, " - "so they must have identical layout"); +extern template class nsTLiteralString; +extern template class nsTLiteralString; + +#endif diff --git a/xpcom/string/nsTPromiseFlatString.cpp b/xpcom/string/nsTPromiseFlatString.cpp index 2e8f1cd5e03b..e671066fbbbd 100644 --- a/xpcom/string/nsTPromiseFlatString.cpp +++ b/xpcom/string/nsTPromiseFlatString.cpp @@ -4,8 +4,9 @@ * 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/. */ +template void -nsTPromiseFlatString_CharT::Init(const substring_type& str) +nsTPromiseFlatString::Init(const substring_type& str) { if (str.IsTerminated()) { char_type* newData = @@ -15,8 +16,8 @@ nsTPromiseFlatString_CharT::Init(const substring_type& str) str.GetDataFlags() & (DataFlags::TERMINATED | DataFlags::LITERAL); // does not promote DataFlags::VOIDED - SetData(newData, newLength, newDataFlags); + this->SetData(newData, newLength, newDataFlags); } else { - Assign(str); + this->Assign(str); } } diff --git a/xpcom/string/nsTPromiseFlatString.h b/xpcom/string/nsTPromiseFlatString.h index d71ce148d490..f6e556ec655b 100644 --- a/xpcom/string/nsTPromiseFlatString.h +++ b/xpcom/string/nsTPromiseFlatString.h @@ -4,6 +4,10 @@ * 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/. */ +#ifndef nsTPromiseFlatString_h +#define nsTPromiseFlatString_h + +#include "nsTString.h" /** * NOTE: @@ -64,11 +68,22 @@ * string (e.g., |nsTString|), the right thing happens. */ -class nsTPromiseFlatString_CharT : public nsTString_CharT +template +class nsTPromiseFlatString : public nsTString { public: - typedef nsTPromiseFlatString_CharT self_type; + typedef nsTPromiseFlatString self_type; + typedef nsTString base_string_type; + typedef typename base_string_type::substring_type substring_type; + typedef typename base_string_type::string_type string_type; + typedef typename base_string_type::substring_tuple_type substring_tuple_type; + typedef typename base_string_type::char_type char_type; + typedef typename base_string_type::size_type size_type; + + // These are only for internal use within the string classes: + typedef typename base_string_type::DataFlags DataFlags; + typedef typename base_string_type::ClassFlags ClassFlags; private: @@ -78,35 +93,55 @@ private: void operator=(const self_type&) = delete; // NOT TO BE IMPLEMENTED - nsTPromiseFlatString_CharT() = delete; + nsTPromiseFlatString() = delete; // NOT TO BE IMPLEMENTED - nsTPromiseFlatString_CharT(const string_type& aStr) = delete; + nsTPromiseFlatString(const string_type& aStr) = delete; public: explicit - nsTPromiseFlatString_CharT(const substring_type& aStr) + nsTPromiseFlatString(const substring_type& aStr) : string_type() { Init(aStr); } explicit - nsTPromiseFlatString_CharT(const substring_tuple_type& aTuple) + nsTPromiseFlatString(const substring_tuple_type& aTuple) : string_type() { // nothing else to do here except assign the value of the tuple // into ourselves. - Assign(aTuple); + this->Assign(aTuple); } }; +extern template class nsTPromiseFlatString; +extern template class nsTPromiseFlatString; + // We template this so that the constructor is chosen based on the type of the // parameter. This allows us to reject attempts to promise a flat flat string. template -const nsTPromiseFlatString_CharT -TPromiseFlatString_CharT(const T& aString) +const nsTPromiseFlatString +TPromiseFlatString(const typename nsTPromiseFlatString::substring_type& aString) { - return nsTPromiseFlatString_CharT(aString); + return nsTPromiseFlatString(aString); } + +template +const nsTPromiseFlatString +TPromiseFlatString(const typename nsTPromiseFlatString::substring_tuple_type& aString) +{ + return nsTPromiseFlatString(aString); +} + +#ifndef PromiseFlatCString +#define PromiseFlatCString TPromiseFlatString +#endif + +#ifndef PromiseFlatString +#define PromiseFlatString TPromiseFlatString +#endif + +#endif diff --git a/xpcom/string/nsTString.cpp b/xpcom/string/nsTString.cpp index 9afb2d30c7de..c864e5302254 100644 --- a/xpcom/string/nsTString.cpp +++ b/xpcom/string/nsTString.cpp @@ -4,13 +4,14 @@ * 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/. */ +template void -nsTString_CharT::Rebind(const char_type* data, size_type length) +nsTString::Rebind(const char_type* data, size_type length) { // If we currently own a buffer, release it. - Finalize(); + this->Finalize(); - SetData(const_cast(data), length, DataFlags::TERMINATED); - AssertValidDependentString(); + this->SetData(const_cast(data), length, DataFlags::TERMINATED); + this->AssertValidDependentString(); } diff --git a/xpcom/string/nsTString.h b/xpcom/string/nsTString.h index 2cce848342e3..4f7396e5599a 100644 --- a/xpcom/string/nsTString.h +++ b/xpcom/string/nsTString.h @@ -5,6 +5,11 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // IWYU pragma: private, include "nsString.h" +#ifndef nsTString_h +#define nsTString_h + +#include "nsTSubstring.h" + /** * This is the canonical null-terminated string class. All subclasses * promise null-terminated storage. Instances of this class allocate @@ -17,11 +22,47 @@ * This class is also known as nsAFlat[C]String, where "flat" is used * to denote a null-terminated string. */ -class nsTString_CharT : public nsTSubstring_CharT +template +class nsTString : public nsTSubstring { public: - typedef nsTString_CharT self_type; + typedef nsTString self_type; + +#ifdef __clang__ + // bindgen w/ clang 3.9 at least chokes on a typedef, but using is okay. + using typename nsTSubstring::substring_type; +#else + // On the other hand msvc chokes on the using statement. It seems others + // don't care either way so we lump them in here. + typedef typename nsTSubstring::substring_type substring_type; +#endif + + typedef typename substring_type::fallible_t fallible_t; + + typedef typename substring_type::char_type char_type; + typedef typename substring_type::char_traits char_traits; + typedef typename substring_type::incompatible_char_type incompatible_char_type; + + typedef typename substring_type::substring_tuple_type substring_tuple_type; + + typedef typename substring_type::const_iterator const_iterator; + typedef typename substring_type::iterator iterator; + + typedef typename substring_type::comparator_type comparator_type; + + typedef typename substring_type::char_iterator char_iterator; + typedef typename substring_type::const_char_iterator const_char_iterator; + + typedef typename substring_type::index_type index_type; + typedef typename substring_type::size_type size_type; + + // These are only for internal use within the string classes: + typedef typename substring_type::DataFlags DataFlags; + typedef typename substring_type::ClassFlags ClassFlags; + + using typename substring_type::IsChar; + using typename substring_type::IsChar16; public: @@ -29,78 +70,80 @@ public: * constructors */ - nsTString_CharT() + nsTString() : substring_type(ClassFlags::NULL_TERMINATED) { } explicit - nsTString_CharT(const char_type* aData, size_type aLength = size_type(-1)) + nsTString(const char_type* aData, size_type aLength = size_type(-1)) : substring_type(ClassFlags::NULL_TERMINATED) { - Assign(aData, aLength); + this->Assign(aData, aLength); } -#if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER) +#if defined(MOZ_USE_CHAR16_WRAPPER) + template explicit - nsTString_CharT(char16ptr_t aStr, size_type aLength = size_type(-1)) + nsTString(char16ptr_t aStr, size_type aLength = size_type(-1)) : substring_type(ClassFlags::NULL_TERMINATED) { - Assign(static_cast(aStr), aLength); + this->Assign(static_cast(aStr), aLength); } #endif - nsTString_CharT(const self_type& aStr) + nsTString(const self_type& aStr) : substring_type(ClassFlags::NULL_TERMINATED) { - Assign(aStr); + this->Assign(aStr); } - MOZ_IMPLICIT nsTString_CharT(const substring_tuple_type& aTuple) + MOZ_IMPLICIT nsTString(const substring_tuple_type& aTuple) : substring_type(ClassFlags::NULL_TERMINATED) { - Assign(aTuple); + this->Assign(aTuple); } explicit - nsTString_CharT(const substring_type& aReadable) + nsTString(const substring_type& aReadable) : substring_type(ClassFlags::NULL_TERMINATED) { - Assign(aReadable); + this->Assign(aReadable); } // |operator=| does not inherit, so we must define our own self_type& operator=(char_type aChar) { - Assign(aChar); + this->Assign(aChar); return *this; } self_type& operator=(const char_type* aData) { - Assign(aData); + this->Assign(aData); return *this; } self_type& operator=(const self_type& aStr) { - Assign(aStr); + this->Assign(aStr); return *this; } -#if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER) +#if defined(MOZ_USE_CHAR16_WRAPPER) + template self_type& operator=(const char16ptr_t aStr) { - Assign(static_cast(aStr)); + this->Assign(static_cast(aStr)); return *this; } #endif self_type& operator=(const substring_type& aStr) { - Assign(aStr); + this->Assign(aStr); return *this; } self_type& operator=(const substring_tuple_type& aTuple) { - Assign(aTuple); + this->Assign(aTuple); return *this; } @@ -108,13 +151,14 @@ public: * returns the null-terminated string */ -#if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER) - MOZ_NO_DANGLING_ON_TEMPORARIES char16ptr_t get() const -#else - MOZ_NO_DANGLING_ON_TEMPORARIES const char_type* get() const + template struct raw_type { typedef const U* type; }; +#if defined(MOZ_USE_CHAR16_WRAPPER) + template <> struct raw_type { typedef char16ptr_t type; }; #endif + + MOZ_NO_DANGLING_ON_TEMPORARIES typename raw_type::type get() const { - return mData; + return this->mData; } @@ -127,8 +171,8 @@ public: char_type CharAt(index_type aIndex) const { - NS_ASSERTION(aIndex <= mLength, "index exceeds allowable range"); - return mData[aIndex]; + NS_ASSERTION(aIndex <= this->mLength, "index exceeds allowable range"); + return this->mData[aIndex]; } char_type operator[](index_type aIndex) const @@ -151,24 +195,25 @@ public: * @return offset in string, or kNotFound */ - int32_t Find(const nsCString& aString, bool aIgnoreCase = false, + int32_t Find(const nsTString& aString, bool aIgnoreCase = false, int32_t aOffset = 0, int32_t aCount = -1) const; int32_t Find(const char* aString, bool aIgnoreCase = false, int32_t aOffset = 0, int32_t aCount = -1) const; -#ifdef CharT_is_PRUnichar - int32_t Find(const nsString& aString, int32_t aOffset = 0, + template + int32_t Find(const self_type& aString, int32_t aOffset = 0, int32_t aCount = -1) const; - int32_t Find(const char16_t* aString, int32_t aOffset = 0, + template + int32_t Find(const char_type* aString, int32_t aOffset = 0, int32_t aCount = -1) const; #ifdef MOZ_USE_CHAR16_WRAPPER + template int32_t Find(char16ptr_t aString, int32_t aOffset = 0, int32_t aCount = -1) const { return Find(static_cast(aString), aOffset, aCount); } #endif -#endif /** @@ -183,17 +228,18 @@ public: * @return offset in string, or kNotFound */ - int32_t RFind(const nsCString& aString, bool aIgnoreCase = false, + // Case aIgnoreCase option only with char versions + int32_t RFind(const nsTString& aString, bool aIgnoreCase = false, int32_t aOffset = -1, int32_t aCount = -1) const; int32_t RFind(const char* aCString, bool aIgnoreCase = false, int32_t aOffset = -1, int32_t aCount = -1) const; -#ifdef CharT_is_PRUnichar - int32_t RFind(const nsString& aString, int32_t aOffset = -1, + template + int32_t RFind(const self_type& aString, int32_t aOffset = -1, int32_t aCount = -1) const; - int32_t RFind(const char16_t* aString, int32_t aOffset = -1, + template + int32_t RFind(const char_type* aString, int32_t aOffset = -1, int32_t aCount = -1) const; -#endif /** @@ -221,15 +267,14 @@ public: * @return offset in string, or kNotFound */ - int32_t FindCharInSet(const char* aString, int32_t aOffset = 0) const; + int32_t FindCharInSet(const char_type* aString, int32_t aOffset = 0) const; int32_t FindCharInSet(const self_type& aString, int32_t aOffset = 0) const { return FindCharInSet(aString.get(), aOffset); } -#ifdef CharT_is_PRUnichar - int32_t FindCharInSet(const char16_t* aString, int32_t aOffset = 0) const; -#endif + template + int32_t FindCharInSet(const char* aSet, int32_t aOffset = 0) const; /** @@ -257,11 +302,9 @@ public: * @param aCount tells us how many chars to compare * @return -1,0,1 */ - -#ifdef CharT_is_char - int32_t Compare(const char* aString, bool aIgnoreCase = false, + template + int32_t Compare(const char_type* aString, bool aIgnoreCase = false, int32_t aCount = -1) const; -#endif /** @@ -272,16 +315,14 @@ public: * @param aCount tells us how many chars to compare * @return boolean */ -#ifdef CharT_is_char - bool EqualsIgnoreCase(const char* aString, int32_t aCount = -1) const + template + bool EqualsIgnoreCase(const char_type* aString, int32_t aCount = -1) const { return Compare(aString, true, aCount) == 0; } -#else - bool EqualsIgnoreCase(const char* aString, int32_t aCount = -1) const; - -#endif // !CharT_is_PRUnichar + template + bool EqualsIgnoreCase(const incompatible_char_type* aString, int32_t aCount = -1) const; /** * Perform string to double-precision float conversion. @@ -297,11 +338,7 @@ public: * @param aErrorCode will contain error if one occurs * @return single-precision float rep of string value */ - float ToFloat(nsresult* aErrorCode) const - { - return (float)ToDouble(aErrorCode); - } - + float ToFloat(nsresult* aErrorCode) const; /** * Perform string to int conversion. @@ -337,7 +374,7 @@ public: * aWritable = Substring(aReadable, 0, 17); */ - size_type Mid(self_type& aResult, uint32_t aStartPos, uint32_t aCount) const; + size_type Mid(self_type& aResult, index_type aStartPos, size_type aCount) const; size_type Left(self_type& aResult, size_type aCount) const { @@ -346,8 +383,8 @@ public: size_type Right(self_type& aResult, size_type aCount) const { - aCount = XPCOM_MIN(mLength, aCount); - return Mid(aResult, mLength - aCount, aCount); + aCount = XPCOM_MIN(this->mLength, aCount); + return Mid(aResult, this->mLength - aCount, aCount); } @@ -368,12 +405,13 @@ public: * * @param aSet -- characters to be cut from this */ -#ifdef CharT_is_PRUnichar - using nsTSubstring_CharT::StripChars; -#endif - void StripChars(const char* aSet); - bool StripChars(const char* aSet, const fallible_t&); + void StripChars(const char_type* aSet); + template + bool StripChars(const incompatible_char_type* aSet, const fallible_t&); + + template + void StripChars(const incompatible_char_type* aSet); /** * This method strips whitespace throughout the string. @@ -387,10 +425,11 @@ public: */ void ReplaceChar(char_type aOldChar, char_type aNewChar); - void ReplaceChar(const char* aSet, char_type aNewChar); -#ifdef CharT_is_PRUnichar - void ReplaceChar(const char16_t* aSet, char16_t aNewChar); -#endif + void ReplaceChar(const char_type* aSet, char_type aNewChar); + + template + void ReplaceChar(const char* aSet, char16_t aNewChar); + /** * Replace all occurrences of aTarget with aNewValue. * The complexity of this function is O(n+m), n being the length of the string @@ -444,9 +483,9 @@ public: */ void AssertValidDependentString() { - NS_ASSERTION(mData, "nsTDependentString must wrap a non-NULL buffer"); - NS_ASSERTION(mLength != size_type(-1), "nsTDependentString has bogus length"); - NS_ASSERTION(mData[mLength] == 0, + NS_ASSERTION(this->mData, "nsTDependentString must wrap a non-NULL buffer"); + NS_ASSERTION(this->mLength != size_type(-1), "nsTDependentString has bogus length"); + NS_ASSERTION(this->mData[substring_type::mLength] == 0, "nsTDependentString must wrap only null-terminated strings. " "You are probably looking for nsTDependentSubstring."); } @@ -455,17 +494,18 @@ public: protected: // allow subclasses to initialize fields directly - nsTString_CharT(char_type* aData, size_type aLength, DataFlags aDataFlags, - ClassFlags aClassFlags) + nsTString(char_type* aData, size_type aLength, DataFlags aDataFlags, + ClassFlags aClassFlags) : substring_type(aData, aLength, aDataFlags, aClassFlags | ClassFlags::NULL_TERMINATED) { } - friend const nsTString_CharT& TNullString_CharT(); + friend const nsTString& NullCString(); + friend const nsTString& NullString(); // Used by Null[C]String. - explicit nsTString_CharT(DataFlags aDataFlags) + explicit nsTString(DataFlags aDataFlags) : substring_type(char_traits::sEmptyBuffer, 0, aDataFlags | DataFlags::TERMINATED, ClassFlags::NULL_TERMINATED) @@ -480,13 +520,33 @@ protected: }; }; +// TODO(erahm): Do something with ToDouble so that we can extern the +// nsTString templates. +//extern template class nsTString; +//extern template class nsTString; -class nsTFixedString_CharT : public nsTString_CharT +template +class nsTFixedString : public nsTString { public: - typedef nsTFixedString_CharT self_type; - typedef nsTFixedString_CharT fixed_string_type; + typedef nsTFixedString self_type; + typedef nsTFixedString fixed_string_type; + + typedef nsTString base_string_type; + typedef typename base_string_type::string_type string_type; + typedef typename base_string_type::char_type char_type; + typedef typename base_string_type::char_traits char_traits; + typedef typename base_string_type::substring_type substring_type; + typedef typename base_string_type::size_type size_type; + typedef typename base_string_type::substring_tuple_type substring_tuple_type; + + // These are only for internal use within the string classes: + typedef typename base_string_type::DataFlags DataFlags; + typedef typename base_string_type::ClassFlags ClassFlags; + + using typename base_string_type::IsChar; + using typename base_string_type::IsChar16; public: @@ -500,7 +560,7 @@ public: * the length of the string already contained in the buffer */ - nsTFixedString_CharT(char_type* aData, size_type aStorageSize) + nsTFixedString(char_type* aData, size_type aStorageSize) : string_type(aData, uint32_t(char_traits::length(aData)), DataFlags::TERMINATED | DataFlags::FIXED, ClassFlags::FIXED) @@ -509,8 +569,8 @@ public: { } - nsTFixedString_CharT(char_type* aData, size_type aStorageSize, - size_type aLength) + nsTFixedString(char_type* aData, size_type aStorageSize, + size_type aLength) : string_type(aData, aLength, DataFlags::TERMINATED | DataFlags::FIXED, ClassFlags::FIXED) , mFixedCapacity(aStorageSize - 1) @@ -523,52 +583,72 @@ public: // |operator=| does not inherit, so we must define our own self_type& operator=(char_type aChar) { - Assign(aChar); + this->Assign(aChar); return *this; } self_type& operator=(const char_type* aData) { - Assign(aData); + this->Assign(aData); return *this; } self_type& operator=(const substring_type& aStr) { - Assign(aStr); + this->Assign(aStr); return *this; } self_type& operator=(const substring_tuple_type& aTuple) { - Assign(aTuple); + this->Assign(aTuple); return *this; } protected: - friend class nsTSubstring_CharT; + friend class nsTSubstring; size_type mFixedCapacity; char_type* mFixedBuf; }; +extern template class nsTFixedString; +extern template class nsTFixedString; /** - * nsTAutoString_CharT + * nsTAutoStringN * - * Subclass of nsTString_CharT that adds support for stack-based string + * Subclass of nsTString that adds support for stack-based string * allocation. It is normally not a good idea to use this class on the * heap, because it will allocate space which may be wasted if the string * it contains is significantly smaller or any larger than 64 characters. * * NAMES: - * nsAutoStringN / nsAutoString for wide characters - * nsAutoCStringN / nsAutoCString for narrow characters + * nsAutoStringN / nsTAutoString for wide characters + * nsAutoCStringN / nsTAutoCString for narrow characters */ -template -class MOZ_NON_MEMMOVABLE nsTAutoStringN_CharT : public nsTFixedString_CharT +template +class MOZ_NON_MEMMOVABLE nsTAutoStringN : public nsTFixedString { public: - typedef nsTAutoStringN_CharT self_type; + typedef nsTAutoStringN self_type; + +#ifdef __clang__ + // bindgen w/ clang 3.9 at least chokes on a typedef, but using is okay. + using typename nsTFixedString::fixed_string_type; +#else + // On the other hand msvc chokes on the using statement. It seems others + // don't care either way so we lump them in here. + typedef typename nsTFixedString::fixed_string_type fixed_string_type; +#endif + + typedef typename fixed_string_type::char_type char_type; + typedef typename fixed_string_type::char_traits char_traits; + typedef typename fixed_string_type::substring_type substring_type; + typedef typename fixed_string_type::size_type size_type; + typedef typename fixed_string_type::substring_tuple_type substring_tuple_type; + + using typename fixed_string_type::IsChar; + using typename fixed_string_type::IsChar16; public: @@ -576,84 +656,85 @@ public: * constructors */ - nsTAutoStringN_CharT() + nsTAutoStringN() : fixed_string_type(mStorage, N, 0) { } explicit - nsTAutoStringN_CharT(char_type aChar) + nsTAutoStringN(char_type aChar) : fixed_string_type(mStorage, N, 0) { - Assign(aChar); + this->Assign(aChar); } explicit - nsTAutoStringN_CharT(const char_type* aData, - size_type aLength = size_type(-1)) + nsTAutoStringN(const char_type* aData, size_type aLength = size_type(-1)) : fixed_string_type(mStorage, N, 0) { - Assign(aData, aLength); + this->Assign(aData, aLength); } -#if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER) +#if defined(MOZ_USE_CHAR16_WRAPPER) + template explicit - nsTAutoStringN_CharT(char16ptr_t aData, size_type aLength = size_type(-1)) - : nsTAutoStringN_CharT(static_cast(aData), aLength) + nsTAutoStringN(char16ptr_t aData, size_type aLength = size_type(-1)) + : nsTAutoStringN(static_cast(aData), aLength) { } #endif - nsTAutoStringN_CharT(const self_type& aStr) + nsTAutoStringN(const self_type& aStr) : fixed_string_type(mStorage, N, 0) { - Assign(aStr); + this->Assign(aStr); } explicit - nsTAutoStringN_CharT(const substring_type& aStr) + nsTAutoStringN(const substring_type& aStr) : fixed_string_type(mStorage, N, 0) { - Assign(aStr); + this->Assign(aStr); } - MOZ_IMPLICIT nsTAutoStringN_CharT(const substring_tuple_type& aTuple) + MOZ_IMPLICIT nsTAutoStringN(const substring_tuple_type& aTuple) : fixed_string_type(mStorage, N, 0) { - Assign(aTuple); + this->Assign(aTuple); } // |operator=| does not inherit, so we must define our own self_type& operator=(char_type aChar) { - Assign(aChar); + this->Assign(aChar); return *this; } self_type& operator=(const char_type* aData) { - Assign(aData); + this->Assign(aData); return *this; } -#if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER) +#if defined(MOZ_USE_CHAR16_WRAPPER) + template self_type& operator=(char16ptr_t aStr) { - Assign(aStr); + this->Assign(aStr); return *this; } #endif self_type& operator=(const self_type& aStr) { - Assign(aStr); + this->Assign(aStr); return *this; } self_type& operator=(const substring_type& aStr) { - Assign(aStr); + this->Assign(aStr); return *this; } self_type& operator=(const substring_tuple_type& aTuple) { - Assign(aTuple); + this->Assign(aTuple); return *this; } @@ -664,9 +745,9 @@ private: char_type mStorage[N]; }; -// We define this typedef instead of providing a default value for N so that so -// there is a default typename that doesn't require angle brackets. -using nsTAutoString_CharT = nsTAutoStringN_CharT; +// Externs for the most common nsTAutoStringN variations. +extern template class nsTAutoStringN; +extern template class nsTAutoStringN; // // nsAutoString stores pointers into itself which are invalidated when an @@ -674,26 +755,26 @@ using nsTAutoString_CharT = nsTAutoStringN_CharT; // elements! // template class nsTArrayElementTraits; -template<> -class nsTArrayElementTraits +template +class nsTArrayElementTraits> { public: template struct Dont_Instantiate_nsTArray_of; template struct Instead_Use_nsTArray_of; - static Dont_Instantiate_nsTArray_of* - Construct(Instead_Use_nsTArray_of* aE) + static Dont_Instantiate_nsTArray_of>* + Construct(Instead_Use_nsTArray_of>* aE) { return 0; } template - static Dont_Instantiate_nsTArray_of* - Construct(Instead_Use_nsTArray_of* aE, const A& aArg) + static Dont_Instantiate_nsTArray_of>* + Construct(Instead_Use_nsTArray_of>* aE, const A& aArg) { return 0; } - static Dont_Instantiate_nsTArray_of* - Destruct(Instead_Use_nsTArray_of* aE) + static Dont_Instantiate_nsTArray_of>* + Destruct(Instead_Use_nsTArray_of>* aE) { return 0; } @@ -727,18 +808,19 @@ public: * // ... * } */ -class MOZ_STACK_CLASS nsTGetterCopies_CharT +template +class MOZ_STACK_CLASS nsTGetterCopies { public: - typedef CharT char_type; + typedef T char_type; - explicit nsTGetterCopies_CharT(nsTSubstring_CharT& aStr) + explicit nsTGetterCopies(nsTSubstring& aStr) : mString(aStr) , mData(nullptr) { } - ~nsTGetterCopies_CharT() + ~nsTGetterCopies() { mString.Adopt(mData); // OK if mData is null } @@ -749,14 +831,16 @@ public: } private: - nsTSubstring_CharT& mString; + nsTSubstring& mString; char_type* mData; }; // See the comment above nsTGetterCopies_CharT for how to use this. -inline nsTGetterCopies_CharT -getter_Copies(nsTSubstring_CharT& aString) +template +inline nsTGetterCopies +getter_Copies(nsTSubstring& aString) { - return nsTGetterCopies_CharT(aString); + return nsTGetterCopies(aString); } +#endif diff --git a/xpcom/string/nsTStringComparator.cpp b/xpcom/string/nsTStringComparator.cpp index 3f383c65f6a2..6fa758940104 100644 --- a/xpcom/string/nsTStringComparator.cpp +++ b/xpcom/string/nsTStringComparator.cpp @@ -4,18 +4,20 @@ * 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/. */ +template int NS_FASTCALL -Compare(const nsTSubstring_CharT::base_string_type& aLhs, - const nsTSubstring_CharT::base_string_type& aRhs, - const nsTStringComparator_CharT& comp) +Compare(const mozilla::detail::nsTStringRepr& aLhs, + const mozilla::detail::nsTStringRepr& aRhs, + const nsTStringComparator& comp) { - typedef nsTSubstring_CharT::size_type size_type; + typedef typename nsTSubstring::size_type size_type; + typedef typename nsTSubstring::const_iterator const_iterator; if (&aLhs == &aRhs) { return 0; } - nsTSubstring_CharT::const_iterator leftIter, rightIter; + const_iterator leftIter, rightIter; aLhs.BeginReading(leftIter); aRhs.BeginReading(rightIter); @@ -38,13 +40,14 @@ Compare(const nsTSubstring_CharT::base_string_type& aLhs, return result; } +template int -nsTDefaultStringComparator_CharT::operator()(const char_type* aLhs, - const char_type* aRhs, - uint32_t aLLength, - uint32_t aRLength) const +nsTDefaultStringComparator::operator()(const char_type* aLhs, + const char_type* aRhs, + uint32_t aLLength, + uint32_t aRLength) const { return - aLLength == aRLength ? nsCharTraits::compare(aLhs, aRhs, aLLength) : + aLLength == aRLength ? nsCharTraits::compare(aLhs, aRhs, aLLength) : (aLLength > aRLength) ? 1 : -1; } diff --git a/xpcom/string/nsTStringObsolete.cpp b/xpcom/string/nsTStringObsolete.cpp index 948880bad3f8..e2e042875c6e 100644 --- a/xpcom/string/nsTStringObsolete.cpp +++ b/xpcom/string/nsTStringObsolete.cpp @@ -14,23 +14,24 @@ * aOffset specifies starting index * aCount specifies number of string compares (iterations) */ - +template int32_t -nsTString_CharT::Find( const nsCString& aString, bool aIgnoreCase, int32_t aOffset, int32_t aCount) const +nsTString::Find(const nsTString& aString, bool aIgnoreCase, int32_t aOffset, int32_t aCount) const { // this method changes the meaning of aOffset and aCount: - Find_ComputeSearchRange(mLength, aString.Length(), aOffset, aCount); + Find_ComputeSearchRange(this->mLength, aString.Length(), aOffset, aCount); - int32_t result = FindSubstring(mData + aOffset, aCount, aString.get(), aString.Length(), aIgnoreCase); + int32_t result = FindSubstring(this->mData + aOffset, aCount, aString.get(), aString.Length(), aIgnoreCase); if (result != kNotFound) result += aOffset; return result; } +template int32_t -nsTString_CharT::Find( const char* aString, bool aIgnoreCase, int32_t aOffset, int32_t aCount) const +nsTString::Find(const char* aString, bool aIgnoreCase, int32_t aOffset, int32_t aCount) const { - return Find(nsDependentCString(aString), aIgnoreCase, aOffset, aCount); + return Find(nsTDependentString(aString), aIgnoreCase, aOffset, aCount); } @@ -40,34 +41,35 @@ nsTString_CharT::Find( const char* aString, bool aIgnoreCase, int32_t aOffset, i * aOffset specifies starting index * aCount specifies number of string compares (iterations) */ - +template int32_t -nsTString_CharT::RFind( const nsCString& aString, bool aIgnoreCase, int32_t aOffset, int32_t aCount) const +nsTString::RFind(const nsTString& aString, bool aIgnoreCase, int32_t aOffset, int32_t aCount) const { // this method changes the meaning of aOffset and aCount: - RFind_ComputeSearchRange(mLength, aString.Length(), aOffset, aCount); + RFind_ComputeSearchRange(this->mLength, aString.Length(), aOffset, aCount); - int32_t result = RFindSubstring(mData + aOffset, aCount, aString.get(), aString.Length(), aIgnoreCase); + int32_t result = RFindSubstring(this->mData + aOffset, aCount, aString.get(), aString.Length(), aIgnoreCase); if (result != kNotFound) result += aOffset; return result; } +template int32_t -nsTString_CharT::RFind( const char* aString, bool aIgnoreCase, int32_t aOffset, int32_t aCount) const +nsTString::RFind(const char* aString, bool aIgnoreCase, int32_t aOffset, int32_t aCount) const { - return RFind(nsDependentCString(aString), aIgnoreCase, aOffset, aCount); + return RFind(nsTDependentString(aString), aIgnoreCase, aOffset, aCount); } /** * nsTString::RFindChar */ - +template int32_t -nsTString_CharT::RFindChar( char16_t aChar, int32_t aOffset, int32_t aCount) const +nsTString::RFindChar(char16_t aChar, int32_t aOffset, int32_t aCount) const { - return nsBufferRoutines::rfind_char(mData, mLength, aOffset, aChar, aCount); + return nsBufferRoutines::rfind_char(this->mData, this->mLength, aOffset, aChar, aCount); } @@ -75,15 +77,16 @@ nsTString_CharT::RFindChar( char16_t aChar, int32_t aOffset, int32_t aCount) con * nsTString::FindCharInSet */ +template int32_t -nsTString_CharT::FindCharInSet( const char* aSet, int32_t aOffset ) const +nsTString::FindCharInSet(const char_type* aSet, int32_t aOffset) const { if (aOffset < 0) aOffset = 0; - else if (aOffset >= int32_t(mLength)) + else if (aOffset >= int32_t(this->mLength)) return kNotFound; - int32_t result = ::FindCharInSet(mData + aOffset, mLength - aOffset, aSet); + int32_t result = ::FindCharInSet(this->mData + aOffset, this->mLength - aOffset, aSet); if (result != kNotFound) result += aOffset; return result; @@ -94,30 +97,32 @@ nsTString_CharT::FindCharInSet( const char* aSet, int32_t aOffset ) const * nsTString::RFindCharInSet */ +template int32_t -nsTString_CharT::RFindCharInSet( const CharT* aSet, int32_t aOffset ) const +nsTString::RFindCharInSet(const char_type* aSet, int32_t aOffset) const { // We want to pass a "data length" to ::RFindCharInSet - if (aOffset < 0 || aOffset > int32_t(mLength)) - aOffset = mLength; + if (aOffset < 0 || aOffset > int32_t(this->mLength)) + aOffset = this->mLength; else ++aOffset; - return ::RFindCharInSet(mData, aOffset, aSet); + return ::RFindCharInSet(this->mData, aOffset, aSet); } // it's a shame to replicate this code. it was done this way in the past // to help performance. this function also gets to keep the rickg style // indentation :-/ +template int32_t -nsTString_CharT::ToInteger( nsresult* aErrorCode, uint32_t aRadix ) const +nsTString::ToInteger(nsresult* aErrorCode, uint32_t aRadix) const { - CharT* cp=mData; - int32_t theRadix=10; // base 10 unless base 16 detected, or overriden (aRadix != kAutoDetect) - int32_t result=0; - bool negate=false; - CharT theChar=0; + char_type* cp = this->mData; + int32_t theRadix = 10; // base 10 unless base 16 detected, or overriden (aRadix != kAutoDetect) + int32_t result = 0; + bool negate = false; + char_type theChar = 0; //initial value, override if we find an integer *aErrorCode=NS_ERROR_ILLEGAL_VALUE; @@ -126,8 +131,8 @@ nsTString_CharT::ToInteger( nsresult* aErrorCode, uint32_t aRadix ) const //begin by skipping over leading chars that shouldn't be part of the number... - CharT* endcp=cp+mLength; - bool done=false; + char_type* endcp=cp+this->mLength; + bool done=false; while((cp int64_t -nsTString_CharT::ToInteger64( nsresult* aErrorCode, uint32_t aRadix ) const +nsTString::ToInteger64(nsresult* aErrorCode, uint32_t aRadix) const { - CharT* cp=mData; + char_type* cp=this->mData; int32_t theRadix=10; // base 10 unless base 16 detected, or overriden (aRadix != kAutoDetect) int64_t result=0; - bool negate=false; - CharT theChar=0; + bool negate=false; + char_type theChar=0; //initial value, override if we find an integer *aErrorCode=NS_ERROR_ILLEGAL_VALUE; @@ -253,8 +259,8 @@ nsTString_CharT::ToInteger64( nsresult* aErrorCode, uint32_t aRadix ) const //begin by skipping over leading chars that shouldn't be part of the number... - CharT* endcp=cp+mLength; - bool done=false; + char_type* endcp=cp+this->mLength; + bool done=false; while((cp +typename nsTString::size_type +nsTString::Mid(self_type& aResult, index_type aStartPos, size_type aLengthToCopy) const { - if (aStartPos == 0 && aLengthToCopy >= mLength) + if (aStartPos == 0 && aLengthToCopy >= this->mLength) aResult = *this; else aResult = Substring(*this, aStartPos, aLengthToCopy); @@ -381,16 +388,17 @@ nsTString_CharT::Mid( self_type& aResult, index_type aStartPos, size_type aLengt * nsTString::SetCharAt */ +template bool -nsTString_CharT::SetCharAt( char16_t aChar, uint32_t aIndex ) +nsTString::SetCharAt(char16_t aChar, uint32_t aIndex) { - if (aIndex >= mLength) + if (aIndex >= this->mLength) return false; - if (!EnsureMutable()) - AllocFailed(mLength); + if (!this->EnsureMutable()) + this->AllocFailed(this->mLength); - mData[aIndex] = CharT(aChar); + this->mData[aIndex] = char_type(aChar); return true; } @@ -399,41 +407,54 @@ nsTString_CharT::SetCharAt( char16_t aChar, uint32_t aIndex ) * nsTString::StripChars,StripChar,StripWhitespace */ +template +template void -nsTString_CharT::StripChars( const char* aSet ) +nsTString::StripChars(const incompatible_char_type* aSet) { if (!StripChars(aSet, mozilla::fallible)) { - AllocFailed(mLength); + this->AllocFailed(this->mLength); } } +template +template bool -nsTString_CharT::StripChars( const char* aSet, const fallible_t& ) +nsTString::StripChars(const incompatible_char_type* aSet, const fallible_t&) { - if (!EnsureMutable()) { + if (!this->EnsureMutable()) { return false; } - mLength = nsBufferRoutines::strip_chars(mData, mLength, aSet); + this->mLength = nsBufferRoutines::strip_chars(this->mData, this->mLength, aSet); return true; } +template void -nsTString_CharT::StripWhitespace() +nsTString::StripChars(const char_type* aSet) +{ + nsTSubstring::StripChars(aSet); +} + +template +void +nsTString::StripWhitespace() { if (!StripWhitespace(mozilla::fallible)) { - AllocFailed(mLength); + this->AllocFailed(this->mLength); } } +template bool -nsTString_CharT::StripWhitespace( const fallible_t& ) +nsTString::StripWhitespace(const fallible_t&) { - if (!EnsureMutable()) { + if (!this->EnsureMutable()) { return false; } - StripTaggedASCII(mozilla::ASCIIMask::MaskWhitespace()); + this->StripTaggedASCII(mozilla::ASCIIMask::MaskWhitespace()); return true; } @@ -441,27 +462,29 @@ nsTString_CharT::StripWhitespace( const fallible_t& ) * nsTString::ReplaceChar,ReplaceSubstring */ +template void -nsTString_CharT::ReplaceChar( char_type aOldChar, char_type aNewChar ) +nsTString::ReplaceChar(char_type aOldChar, char_type aNewChar) { - if (!EnsureMutable()) // XXX do this lazily? - AllocFailed(mLength); + if (!this->EnsureMutable()) // XXX do this lazily? + this->AllocFailed(this->mLength); - for (uint32_t i=0; imLength; ++i) { - if (mData[i] == aOldChar) - mData[i] = aNewChar; + if (this->mData[i] == aOldChar) + this->mData[i] = aNewChar; } } +template void -nsTString_CharT::ReplaceChar( const char* aSet, char_type aNewChar ) +nsTString::ReplaceChar(const char_type* aSet, char_type aNewChar) { - if (!EnsureMutable()) // XXX do this lazily? - AllocFailed(mLength); + if (!this->EnsureMutable()) // XXX do this lazily? + this->AllocFailed(this->mLength); - char_type* data = mData; - uint32_t lenRemaining = mLength; + char_type* data = this->mData; + uint32_t lenRemaining = this->mLength; while (lenRemaining) { @@ -477,39 +500,43 @@ nsTString_CharT::ReplaceChar( const char* aSet, char_type aNewChar ) void ReleaseData(void* aData, nsAString::DataFlags aFlags); +template void -nsTString_CharT::ReplaceSubstring(const char_type* aTarget, - const char_type* aNewValue) +nsTString::ReplaceSubstring(const char_type* aTarget, + const char_type* aNewValue) { - ReplaceSubstring(nsTDependentString_CharT(aTarget), - nsTDependentString_CharT(aNewValue)); + ReplaceSubstring(nsTDependentString(aTarget), + nsTDependentString(aNewValue)); } +template bool -nsTString_CharT::ReplaceSubstring(const char_type* aTarget, - const char_type* aNewValue, - const fallible_t& aFallible) +nsTString::ReplaceSubstring(const char_type* aTarget, + const char_type* aNewValue, + const fallible_t& aFallible) { - return ReplaceSubstring(nsTDependentString_CharT(aTarget), - nsTDependentString_CharT(aNewValue), + return ReplaceSubstring(nsTDependentString(aTarget), + nsTDependentString(aNewValue), aFallible); } +template void -nsTString_CharT::ReplaceSubstring(const self_type& aTarget, - const self_type& aNewValue) +nsTString::ReplaceSubstring(const self_type& aTarget, + const self_type& aNewValue) { if (!ReplaceSubstring(aTarget, aNewValue, mozilla::fallible)) { // Note that this may wildly underestimate the allocation that failed, as // we could have been replacing multiple copies of aTarget. - AllocFailed(mLength + (aNewValue.Length() - aTarget.Length())); + this->AllocFailed(this->mLength + (aNewValue.Length() - aTarget.Length())); } } +template bool -nsTString_CharT::ReplaceSubstring(const self_type& aTarget, - const self_type& aNewValue, - const fallible_t&) +nsTString::ReplaceSubstring(const self_type& aTarget, + const self_type& aNewValue, + const fallible_t&) { if (aTarget.Length() == 0) return true; @@ -520,8 +547,8 @@ nsTString_CharT::ReplaceSubstring(const self_type& aTarget, mozilla::CheckedUint32 newLength; while (true) { - int32_t r = FindSubstring(mData + i, mLength - i, static_cast(aTarget.Data()), aTarget.Length(), false); - int32_t until = (r == kNotFound) ? mLength - i : r; + int32_t r = FindSubstring(this->mData + i, this->mLength - i, static_cast(aTarget.Data()), aTarget.Length(), false); + int32_t until = (r == kNotFound) ? this->mLength - i : r; nonMatching.AppendElement(Segment(i, until)); newLength += until; if (r == kNotFound) { @@ -530,10 +557,10 @@ nsTString_CharT::ReplaceSubstring(const self_type& aTarget, newLength += aNewValue.Length(); i += r + aTarget.Length(); - if (i >= mLength) { + if (i >= this->mLength) { // Add an auxiliary entry at the end of the list to help as an edge case // for the algorithms below. - nonMatching.AppendElement(Segment(mLength, 0)); + nonMatching.AppendElement(Segment(this->mLength, 0)); break; } } @@ -545,22 +572,22 @@ nsTString_CharT::ReplaceSubstring(const self_type& aTarget, // If there's only one non-matching segment, then the target string was not // found, and there's nothing to do. if (nonMatching.Length() == 1) { - MOZ_ASSERT(nonMatching[0].mBegin == 0 && nonMatching[0].mLength == mLength, + MOZ_ASSERT(nonMatching[0].mBegin == 0 && nonMatching[0].mLength == this->mLength, "We should have the correct non-matching segment."); return true; } // Make sure that we can mutate our buffer. - // Note that we always allocate at least an mLength sized buffer, because the + // Note that we always allocate at least an this->mLength sized buffer, because the // rest of the algorithm relies on having access to all of the original // string. In other words, we over-allocate in the shrinking case. char_type* oldData; DataFlags oldFlags; - if (!MutatePrep(XPCOM_MAX(mLength, newLength.value()), &oldData, &oldFlags)) + if (!this->MutatePrep(XPCOM_MAX(this->mLength, newLength.value()), &oldData, &oldFlags)) return false; if (oldData) { // Copy all of the old data to the new buffer. - char_traits::copy(mData, oldData, mLength); + char_traits::copy(this->mData, oldData, this->mLength); ::ReleaseData(oldData, oldFlags); } @@ -571,8 +598,8 @@ nsTString_CharT::ReplaceSubstring(const self_type& aTarget, // When we move the i'th non-matching segment into position, we need to // account for the characters deleted by the previous |i| replacements by // subtracting |i * delta|. - const char_type* sourceSegmentPtr = mData + nonMatching[i].mBegin; - char_type* destinationSegmentPtr = mData + nonMatching[i].mBegin - i * delta; + const char_type* sourceSegmentPtr = this->mData + nonMatching[i].mBegin; + char_type* destinationSegmentPtr = this->mData + nonMatching[i].mBegin - i * delta; // Write the i'th replacement immediately before the new i'th non-matching // segment. char_traits::copy(destinationSegmentPtr - aNewValue.Length(), @@ -587,8 +614,8 @@ nsTString_CharT::ReplaceSubstring(const self_type& aTarget, // When we move the i'th non-matching segment into position, we need to // account for the characters added by the previous |i| replacements by // adding |i * delta|. - const char_type* sourceSegmentPtr = mData + nonMatching[i].mBegin; - char_type* destinationSegmentPtr = mData + nonMatching[i].mBegin + i * delta; + const char_type* sourceSegmentPtr = this->mData + nonMatching[i].mBegin; + char_type* destinationSegmentPtr = this->mData + nonMatching[i].mBegin + i * delta; char_traits::move(destinationSegmentPtr, sourceSegmentPtr, nonMatching[i].mLength); // Write the i'th replacement immediately before the new i'th non-matching @@ -599,8 +626,8 @@ nsTString_CharT::ReplaceSubstring(const self_type& aTarget, } // Adjust the length and make sure the string is null terminated. - mLength = newLength.value(); - mData[mLength] = char_type(0); + this->mLength = newLength.value(); + this->mData[this->mLength] = char_type(0); return true; } @@ -609,19 +636,20 @@ nsTString_CharT::ReplaceSubstring(const self_type& aTarget, * nsTString::Trim */ +template void -nsTString_CharT::Trim( const char* aSet, bool aTrimLeading, bool aTrimTrailing, bool aIgnoreQuotes ) +nsTString::Trim(const char* aSet, bool aTrimLeading, bool aTrimTrailing, bool aIgnoreQuotes) { // the old implementation worried about aSet being null :-/ if (!aSet) return; - char_type* start = mData; - char_type* end = mData + mLength; + char_type* start = this->mData; + char_type* end = this->mData + this->mLength; // skip over quotes if requested - if (aIgnoreQuotes && mLength > 2 && mData[0] == mData[mLength - 1] && - (mData[0] == '\'' || mData[0] == '"')) + if (aIgnoreQuotes && this->mLength > 2 && this->mData[0] == this->mData[this->mLength - 1] && + (this->mData[0] == '\'' || this->mData[0] == '"')) { ++start; --end; @@ -631,7 +659,7 @@ nsTString_CharT::Trim( const char* aSet, bool aTrimLeading, bool aTrimTrailing, if (aTrimLeading) { - uint32_t cutStart = start - mData; + uint32_t cutStart = start - this->mData; uint32_t cutLength = 0; // walk forward from start to end @@ -644,17 +672,17 @@ nsTString_CharT::Trim( const char* aSet, bool aTrimLeading, bool aTrimTrailing, if (cutLength) { - Cut(cutStart, cutLength); + this->Cut(cutStart, cutLength); // reset iterators - start = mData + cutStart; - end = mData + mLength - cutStart; + start = this->mData + cutStart; + end = this->mData + this->mLength - cutStart; } } if (aTrimTrailing) { - uint32_t cutEnd = end - mData; + uint32_t cutEnd = end - this->mData; uint32_t cutLength = 0; // walk backward from end to start @@ -667,7 +695,7 @@ nsTString_CharT::Trim( const char* aSet, bool aTrimLeading, bool aTrimTrailing, } if (cutLength) - Cut(cutEnd - cutLength, cutLength); + this->Cut(cutEnd - cutLength, cutLength); } } @@ -676,22 +704,23 @@ nsTString_CharT::Trim( const char* aSet, bool aTrimLeading, bool aTrimTrailing, * nsTString::CompressWhitespace. */ +template void -nsTString_CharT::CompressWhitespace( bool aTrimLeading, bool aTrimTrailing ) +nsTString::CompressWhitespace(bool aTrimLeading, bool aTrimTrailing) { // Quick exit - if (mLength == 0) { + if (this->mLength == 0) { return; } - if (!EnsureMutable()) - AllocFailed(mLength); + if (!this->EnsureMutable()) + this->AllocFailed(this->mLength); const ASCIIMaskArray& mask = mozilla::ASCIIMask::MaskWhitespace(); - char_type* to = mData; - char_type* from = mData; - char_type* end = mData + mLength; + char_type* to = this->mData; + char_type* from = this->mData; + char_type* end = this->mData + this->mLength; // Compresses runs of whitespace down to a normal space ' ' and convert // any whitespace to a normal space. This assumes that whitespace is @@ -711,10 +740,10 @@ nsTString_CharT::CompressWhitespace( bool aTrimLeading, bool aTrimTrailing ) } // If we need to trim the trailing whitespace, back up one character. - if (aTrimTrailing && skipWS && to > mData) { + if (aTrimTrailing && skipWS && to > this->mData) { to--; } *to = char_type(0); // add the null - mLength = to - mData; + this->mLength = to - this->mData; } diff --git a/xpcom/string/nsTStringRepr.h b/xpcom/string/nsTStringRepr.h new file mode 100644 index 000000000000..01daa49ec319 --- /dev/null +++ b/xpcom/string/nsTStringRepr.h @@ -0,0 +1,374 @@ +/* -*- 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/. */ + +#ifndef nsTStringRepr_h +#define nsTStringRepr_h + +#include // std::enable_if + +#include "nsStringFlags.h" +#include "nsCharTraits.h" + +template class nsTSubstringTuple; + +// The base for string comparators +template class nsTStringComparator +{ +public: + typedef T char_type; + + nsTStringComparator() {} + + virtual int operator()(const char_type*, const char_type*, + uint32_t, uint32_t) const = 0; +}; + +// The default string comparator (case-sensitive comparision) +template class nsTDefaultStringComparator + : public nsTStringComparator +{ +public: + typedef T char_type; + + nsTDefaultStringComparator() {} + + virtual int operator()(const char_type*, const char_type*, + uint32_t, uint32_t) const override; +}; + +extern template class nsTDefaultStringComparator; +extern template class nsTDefaultStringComparator; + +namespace mozilla { +namespace detail { + +// nsTStringRepr defines a string's memory layout and some accessor methods. +// This class exists so that nsTLiteralString can avoid inheriting +// nsTSubstring's destructor. All methods on this class must be const because +// literal strings are not writable. +// +// This class is an implementation detail and should not be instantiated +// directly, nor used in any way outside of the string code itself. It is +// buried in a namespace to discourage its use in function parameters. +// If you need to take a parameter, use [const] ns[C]Substring&. +// If you need to instantiate a string, use ns[C]String or descendents. +// +// NAMES: +// nsStringRepr for wide characters +// nsCStringRepr for narrow characters +template class nsTStringRepr +{ +public: + typedef mozilla::fallible_t fallible_t; + + typedef T char_type; + + typedef nsCharTraits char_traits; + typedef typename char_traits::incompatible_char_type incompatible_char_type; + + typedef nsTStringRepr self_type; + typedef self_type base_string_type; + + typedef nsTSubstring substring_type; + typedef nsTSubstringTuple substring_tuple_type; + + typedef nsReadingIterator const_iterator; + typedef nsWritingIterator iterator; + + typedef nsTStringComparator comparator_type; + + typedef char_type* char_iterator; + typedef const char_type* const_char_iterator; + + typedef uint32_t index_type; + typedef uint32_t size_type; + + // These are only for internal use within the string classes: + typedef StringDataFlags DataFlags; + typedef StringClassFlags ClassFlags; + + // These are used to conditionally enable functions for specific character + // types. + using IsChar = std::enable_if::value>; + using IsChar16 = std::enable_if::value>; + + // 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; + } + + // Accessors. + template struct raw_type { typedef const U* type; }; +#if defined(MOZ_USE_CHAR16_WRAPPER) + template <> struct raw_type { typedef char16ptr_t type; }; +#endif + + // Returns pointer to string data (not necessarily null-terminated) + const typename raw_type::type Data() const + { + return mData; + } + + size_type Length() const + { + return mLength; + } + + DataFlags GetDataFlags() const + { + return mDataFlags; + } + + bool IsEmpty() const + { + return mLength == 0; + } + + bool IsLiteral() const + { + return !!(mDataFlags & DataFlags::LITERAL); + } + + bool IsVoid() const + { + return !!(mDataFlags & DataFlags::VOIDED); + } + + bool IsTerminated() const + { + return !!(mDataFlags & DataFlags::TERMINATED); + } + + 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; + + char_type Last() const; + + size_type NS_FASTCALL CountChar(char_type) const; + int32_t NS_FASTCALL FindChar(char_type, index_type aOffset = 0) const; + + inline bool Contains(char_type aChar) const + { + return FindChar(aChar) != kNotFound; + } + + // 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 substring_tuple_type& aTuple) const; + bool NS_FASTCALL Equals(const substring_tuple_type& aTuple, + const comparator_type& aComp) 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(MOZ_USE_CHAR16_WRAPPER) + template + bool NS_FASTCALL Equals(char16ptr_t aData) const + { + return Equals(static_cast(aData)); + } + template + bool NS_FASTCALL Equals(char16ptr_t aData, const comparator_type& aComp) const + { + return Equals(static_cast(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 + 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 + bool LowerCaseEqualsLiteral(const char (&aStr)[N]) const + { + return LowerCaseEqualsASCII(aStr, N - 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); + } + +protected: + nsTStringRepr() = delete; // Never instantiate directly + + constexpr + nsTStringRepr(char_type* aData, size_type aLength, + DataFlags aDataFlags, ClassFlags aClassFlags) + : mData(aData) + , mLength(aLength) + , mDataFlags(aDataFlags) + , mClassFlags(aClassFlags) + { + } + + char_type* mData; + size_type mLength; + DataFlags mDataFlags; + ClassFlags const mClassFlags; +}; + +extern template class nsTStringRepr; +extern template class nsTStringRepr; + +} // namespace detail +} // namespace mozilla + +template +int NS_FASTCALL +Compare(const mozilla::detail::nsTStringRepr& aLhs, + const mozilla::detail::nsTStringRepr& aRhs, + const nsTStringComparator& = nsTDefaultStringComparator()); + +template +inline bool +operator!=(const mozilla::detail::nsTStringRepr& aLhs, + const mozilla::detail::nsTStringRepr& aRhs) +{ + return !aLhs.Equals(aRhs); +} + +template +inline bool +operator!=(const mozilla::detail::nsTStringRepr& aLhs, + const T* aRhs) +{ + return !aLhs.Equals(aRhs); +} + +template +inline bool +operator<(const mozilla::detail::nsTStringRepr& aLhs, + const mozilla::detail::nsTStringRepr& aRhs) +{ + return Compare(aLhs, aRhs) < 0; +} + +template +inline bool +operator<=(const mozilla::detail::nsTStringRepr& aLhs, + const mozilla::detail::nsTStringRepr& aRhs) +{ + return Compare(aLhs, aRhs) <= 0; +} + +template +inline bool +operator==(const mozilla::detail::nsTStringRepr& aLhs, + const mozilla::detail::nsTStringRepr& aRhs) +{ + return aLhs.Equals(aRhs); +} + +template +inline bool +operator==(const mozilla::detail::nsTStringRepr& aLhs, + const T* aRhs) +{ + return aLhs.Equals(aRhs); +} + +template +inline bool +operator>=(const mozilla::detail::nsTStringRepr& aLhs, + const mozilla::detail::nsTStringRepr& aRhs) +{ + return Compare(aLhs, aRhs) >= 0; +} + +template +inline bool +operator>(const mozilla::detail::nsTStringRepr& aLhs, + const mozilla::detail::nsTStringRepr& aRhs) +{ + return Compare(aLhs, aRhs) > 0; +} + +#endif diff --git a/xpcom/string/nsTSubstring.cpp b/xpcom/string/nsTSubstring.cpp index 3238b9b1bb1e..728e82a90068 100644 --- a/xpcom/string/nsTSubstring.cpp +++ b/xpcom/string/nsTSubstring.cpp @@ -12,23 +12,25 @@ using double_conversion::DoubleToStringConverter; -const nsTSubstring_CharT::size_type nsTSubstring_CharT::kMaxCapacity = - (nsTSubstring_CharT::size_type(-1) / +template +const typename nsTSubstring::size_type nsTSubstring::kMaxCapacity = + (nsTSubstring::size_type(-1) / 2 - sizeof(nsStringBuffer)) / - sizeof(nsTSubstring_CharT::char_type) - 2; + sizeof(nsTSubstring::char_type) - 2; #ifdef XPCOM_STRING_CONSTRUCTOR_OUT_OF_LINE -nsTSubstring_CharT::nsTSubstring_CharT(char_type* aData, size_type aLength, - DataFlags aDataFlags, - ClassFlags aClassFlags) - : nsTStringRepr_CharT(aData, aLength, aDataFlags, aClassFlags) +template +nsTSubstring::nsTSubstring(char_type* aData, size_type aLength, + DataFlags aDataFlags, + ClassFlags aClassFlags) + : ::mozilla::detail::nsTStringRepr(aData, aLength, aDataFlags, aClassFlags) { AssertValid(); MOZ_RELEASE_ASSERT(CheckCapacity(aLength), "String is too large."); if (aDataFlags & DataFlags::OWNED) { STRING_STAT_INCREMENT(Adopt); - MOZ_LOG_CTOR(mData, "StringAdopt", 1); + MOZ_LOG_CTOR(this->mData, "StringAdopt", 1); } } #endif /* XPCOM_STRING_CONSTRUCTOR_OUT_OF_LINE */ @@ -36,10 +38,11 @@ nsTSubstring_CharT::nsTSubstring_CharT(char_type* aData, size_type aLength, /** * helper function for down-casting a nsTSubstring to a nsTFixedString. */ -inline const nsTFixedString_CharT* -AsFixedString(const nsTSubstring_CharT* aStr) +template +inline const nsTFixedString* +AsFixedString(const nsTSubstring* aStr) { - return static_cast(aStr); + return static_cast*>(aStr); } /** @@ -49,9 +52,10 @@ AsFixedString(const nsTSubstring_CharT* aStr) * returns the old data and old flags members if mData is newly allocated. * the old data must be released by the caller. */ +template bool -nsTSubstring_CharT::MutatePrep(size_type aCapacity, char_type** aOldData, - DataFlags* aOldDataFlags) +nsTSubstring::MutatePrep(size_type aCapacity, char_type** aOldData, + DataFlags* aOldDataFlags) { // initialize to no old data *aOldData = nullptr; @@ -74,7 +78,7 @@ nsTSubstring_CharT::MutatePrep(size_type aCapacity, char_type** aOldData, if (curCapacity != 0) { if (aCapacity <= curCapacity) { - mDataFlags &= ~DataFlags::VOIDED; // mutation clears voided flag + this->mDataFlags &= ~DataFlags::VOIDED; // mutation clears voided flag return true; } } @@ -115,9 +119,9 @@ nsTSubstring_CharT::MutatePrep(size_type aCapacity, char_type** aOldData, // // several cases: // - // (1) we have a shared buffer (mDataFlags & DataFlags::SHARED) - // (2) we have an owned buffer (mDataFlags & DataFlags::OWNED) - // (3) we have a fixed buffer (mDataFlags & DataFlags::FIXED) + // (1) we have a shared buffer (this->mDataFlags & DataFlags::SHARED) + // (2) we have an owned buffer (this->mDataFlags & DataFlags::OWNED) + // (3) we have a fixed buffer (this->mDataFlags & DataFlags::FIXED) // (4) we have a readonly buffer // // requiring that we in some cases preserve the data before creating @@ -127,8 +131,8 @@ nsTSubstring_CharT::MutatePrep(size_type aCapacity, char_type** aOldData, size_type storageSize = (aCapacity + 1) * sizeof(char_type); // case #1 - if (mDataFlags & DataFlags::SHARED) { - nsStringBuffer* hdr = nsStringBuffer::FromData(mData); + if (this->mDataFlags & DataFlags::SHARED) { + nsStringBuffer* hdr = nsStringBuffer::FromData(this->mData); if (!hdr->IsReadonly()) { nsStringBuffer* newHdr = nsStringBuffer::Realloc(hdr, storageSize); if (!newHdr) { @@ -136,8 +140,8 @@ nsTSubstring_CharT::MutatePrep(size_type aCapacity, char_type** aOldData, } hdr = newHdr; - mData = (char_type*)hdr->Data(); - mDataFlags &= ~DataFlags::VOIDED; // mutation clears voided flag + this->mData = (char_type*)hdr->Data(); + this->mDataFlags &= ~DataFlags::VOIDED; // mutation clears voided flag return true; } } @@ -147,7 +151,7 @@ nsTSubstring_CharT::MutatePrep(size_type aCapacity, char_type** aOldData, // if we have a fixed buffer of sufficient size, then use it. this helps // avoid heap allocations. - if ((mClassFlags & ClassFlags::FIXED) && + if ((this->mClassFlags & ClassFlags::FIXED) && (aCapacity < AsFixedString(this)->mFixedCapacity)) { newData = AsFixedString(this)->mFixedBuf; newDataFlags = DataFlags::TERMINATED | DataFlags::FIXED; @@ -167,11 +171,11 @@ nsTSubstring_CharT::MutatePrep(size_type aCapacity, char_type** aOldData, } // save old data and flags - *aOldData = mData; - *aOldDataFlags = mDataFlags; + *aOldData = this->mData; + *aOldDataFlags = this->mDataFlags; - // mLength does not change - SetData(newData, mLength, newDataFlags); + // this->mLength does not change + SetData(newData, this->mLength, newDataFlags); // though we are not necessarily terminated at the moment, now is probably // still the best time to set DataFlags::TERMINATED. @@ -179,31 +183,33 @@ nsTSubstring_CharT::MutatePrep(size_type aCapacity, char_type** aOldData, return true; } +template void -nsTSubstring_CharT::Finalize() +nsTSubstring::Finalize() { - ::ReleaseData(mData, mDataFlags); - // mData, mLength, and mDataFlags are purposefully left dangling + ::ReleaseData(this->mData, this->mDataFlags); + // this->mData, this->mLength, and this->mDataFlags are purposefully left dangling } +template bool -nsTSubstring_CharT::ReplacePrep(index_type aCutStart, - size_type aCutLength, - size_type aNewLength) +nsTSubstring::ReplacePrep(index_type aCutStart, + size_type aCutLength, + size_type aNewLength) { - aCutLength = XPCOM_MIN(aCutLength, mLength - aCutStart); + aCutLength = XPCOM_MIN(aCutLength, this->mLength - aCutStart); - mozilla::CheckedInt newTotalLen = mLength; + mozilla::CheckedInt newTotalLen = this->mLength; newTotalLen += aNewLength; newTotalLen -= aCutLength; if (!newTotalLen.isValid()) { return false; } - if (aCutStart == mLength && Capacity() > newTotalLen.value()) { - mDataFlags &= ~DataFlags::VOIDED; - mData[newTotalLen.value()] = char_type(0); - mLength = newTotalLen.value(); + if (aCutStart == this->mLength && Capacity() > newTotalLen.value()) { + this->mDataFlags &= ~DataFlags::VOIDED; + this->mData[newTotalLen.value()] = char_type(0); + this->mLength = newTotalLen.value(); return true; } @@ -211,9 +217,10 @@ nsTSubstring_CharT::ReplacePrep(index_type aCutStart, newTotalLen.value()); } +template bool -nsTSubstring_CharT::ReplacePrepInternal(index_type aCutStart, size_type aCutLen, - size_type aFragLen, size_type aNewLen) +nsTSubstring::ReplacePrepInternal(index_type aCutStart, size_type aCutLen, + size_type aFragLen, size_type aNewLen) { char_type* oldData; DataFlags oldFlags; @@ -227,15 +234,15 @@ nsTSubstring_CharT::ReplacePrepInternal(index_type aCutStart, size_type aCutLen, if (aCutStart > 0) { // copy prefix from old string - char_traits::copy(mData, oldData, aCutStart); + char_traits::copy(this->mData, oldData, aCutStart); } - if (aCutStart + aCutLen < mLength) { + if (aCutStart + aCutLen < this->mLength) { // copy suffix from old string to new offset size_type from = aCutStart + aCutLen; - size_type fromLen = mLength - from; + size_type fromLen = this->mLength - from; uint32_t to = aCutStart + aFragLen; - char_traits::copy(mData + to, oldData + from, fromLen); + char_traits::copy(this->mData + to, oldData + from, fromLen); } ::ReleaseData(oldData, oldFlags); @@ -244,44 +251,45 @@ nsTSubstring_CharT::ReplacePrepInternal(index_type aCutStart, size_type aCutLen, // determine whether or not we need to move part of the existing string // to make room for the requested hole. - if (aFragLen != aCutLen && aCutStart + aCutLen < mLength) { + if (aFragLen != aCutLen && aCutStart + aCutLen < this->mLength) { uint32_t from = aCutStart + aCutLen; - uint32_t fromLen = mLength - from; + uint32_t fromLen = this->mLength - from; uint32_t to = aCutStart + aFragLen; - char_traits::move(mData + to, mData + from, fromLen); + char_traits::move(this->mData + to, this->mData + from, fromLen); } } - // add null terminator (mutable mData always has room for the null- + // add null terminator (mutable this->mData always has room for the null- // terminator). - mData[aNewLen] = char_type(0); - mLength = aNewLen; + this->mData[aNewLen] = char_type(0); + this->mLength = aNewLen; return true; } -nsTSubstring_CharT::size_type -nsTSubstring_CharT::Capacity() const +template +typename nsTSubstring::size_type +nsTSubstring::Capacity() const { // return 0 to indicate an immutable or 0-sized buffer size_type capacity; - if (mDataFlags & DataFlags::SHARED) { + if (this->mDataFlags & DataFlags::SHARED) { // if the string is readonly, then we pretend that it has no capacity. - nsStringBuffer* hdr = nsStringBuffer::FromData(mData); + nsStringBuffer* hdr = nsStringBuffer::FromData(this->mData); if (hdr->IsReadonly()) { capacity = 0; } else { capacity = (hdr->StorageSize() / sizeof(char_type)) - 1; } - } else if (mDataFlags & DataFlags::FIXED) { + } else if (this->mDataFlags & DataFlags::FIXED) { capacity = AsFixedString(this)->mFixedCapacity; - } else if (mDataFlags & DataFlags::OWNED) { + } else if (this->mDataFlags & DataFlags::OWNED) { // we don't store the capacity of an adopted buffer because that would // require an additional member field. the best we can do is base the // capacity on our length. remains to be seen if this is the right // trade-off. - capacity = mLength; + capacity = this->mLength; } else { capacity = 0; } @@ -289,19 +297,20 @@ nsTSubstring_CharT::Capacity() const return capacity; } +template bool -nsTSubstring_CharT::EnsureMutable(size_type aNewLen) +nsTSubstring::EnsureMutable(size_type aNewLen) { - if (aNewLen == size_type(-1) || aNewLen == mLength) { - if (mDataFlags & (DataFlags::FIXED | DataFlags::OWNED)) { + if (aNewLen == size_type(-1) || aNewLen == this->mLength) { + if (this->mDataFlags & (DataFlags::FIXED | DataFlags::OWNED)) { return true; } - if ((mDataFlags & DataFlags::SHARED) && - !nsStringBuffer::FromData(mData)->IsReadonly()) { + if ((this->mDataFlags & DataFlags::SHARED) && + !nsStringBuffer::FromData(this->mData)->IsReadonly()) { return true; } - aNewLen = mLength; + aNewLen = this->mLength; } return SetLength(aNewLen, mozilla::fallible); } @@ -309,43 +318,48 @@ nsTSubstring_CharT::EnsureMutable(size_type aNewLen) // --------------------------------------------------------------------------- // This version of Assign is optimized for single-character assignment. +template void -nsTSubstring_CharT::Assign(char_type aChar) +nsTSubstring::Assign(char_type aChar) { - if (!ReplacePrep(0, mLength, 1)) { - AllocFailed(mLength); + if (!ReplacePrep(0, this->mLength, 1)) { + AllocFailed(this->mLength); } - *mData = aChar; + *this->mData = aChar; } +template bool -nsTSubstring_CharT::Assign(char_type aChar, const fallible_t&) +nsTSubstring::Assign(char_type aChar, const fallible_t&) { - if (!ReplacePrep(0, mLength, 1)) { + if (!ReplacePrep(0, this->mLength, 1)) { return false; } - *mData = aChar; + *this->mData = aChar; return true; } +template void -nsTSubstring_CharT::Assign(const char_type* aData) +nsTSubstring::Assign(const char_type* aData) { if (!Assign(aData, mozilla::fallible)) { AllocFailed(char_traits::length(aData)); } } +template bool -nsTSubstring_CharT::Assign(const char_type* aData, const fallible_t&) +nsTSubstring::Assign(const char_type* aData, const fallible_t&) { return Assign(aData, size_type(-1), mozilla::fallible); } +template void -nsTSubstring_CharT::Assign(const char_type* aData, size_type aLength) +nsTSubstring::Assign(const char_type* aData, size_type aLength) { if (!Assign(aData, aLength, mozilla::fallible)) { AllocFailed(aLength == size_type(-1) ? char_traits::length(aData) @@ -353,9 +367,10 @@ nsTSubstring_CharT::Assign(const char_type* aData, size_type aLength) } } +template bool -nsTSubstring_CharT::Assign(const char_type* aData, size_type aLength, - const fallible_t& aFallible) +nsTSubstring::Assign(const char_type* aData, size_type aLength, + const fallible_t& aFallible) { if (!aData || aLength == 0) { Truncate(); @@ -366,64 +381,69 @@ nsTSubstring_CharT::Assign(const char_type* aData, size_type aLength, aLength = char_traits::length(aData); } - if (IsDependentOn(aData, aData + aLength)) { + if (this->IsDependentOn(aData, aData + aLength)) { return Assign(string_type(aData, aLength), aFallible); } - if (!ReplacePrep(0, mLength, aLength)) { + if (!ReplacePrep(0, this->mLength, aLength)) { return false; } - char_traits::copy(mData, aData, aLength); + char_traits::copy(this->mData, aData, aLength); return true; } +template void -nsTSubstring_CharT::AssignASCII(const char* aData, size_type aLength) +nsTSubstring::AssignASCII(const char* aData, size_type aLength) { if (!AssignASCII(aData, aLength, mozilla::fallible)) { AllocFailed(aLength); } } +template bool -nsTSubstring_CharT::AssignASCII(const char* aData, size_type aLength, +nsTSubstring::AssignASCII(const char* aData, size_type aLength, const fallible_t& aFallible) { // A Unicode string can't depend on an ASCII string buffer, // so this dependence check only applies to CStrings. #ifdef CharT_is_char - if (IsDependentOn(aData, aData + aLength)) { + if (this->IsDependentOn(aData, aData + aLength)) { return Assign(string_type(aData, aLength), aFallible); } #endif - if (!ReplacePrep(0, mLength, aLength)) { + if (!ReplacePrep(0, this->mLength, aLength)) { return false; } - char_traits::copyASCII(mData, aData, aLength); + char_traits::copyASCII(this->mData, aData, aLength); return true; } +template void -nsTSubstring_CharT::AssignLiteral(const char_type* aData, size_type aLength) +nsTSubstring::AssignLiteral(const char_type* aData, size_type aLength) { - ::ReleaseData(mData, mDataFlags); + ::ReleaseData(this->mData, this->mDataFlags); SetData(const_cast(aData), aLength, DataFlags::TERMINATED | DataFlags::LITERAL); } +template void -nsTSubstring_CharT::Assign(const self_type& aStr) +nsTSubstring::Assign(const self_type& aStr) { if (!Assign(aStr, mozilla::fallible)) { AllocFailed(aStr.Length()); } } +template bool -nsTSubstring_CharT::Assign(const self_type& aStr, const fallible_t& aFallible) +nsTSubstring::Assign(const self_type& aStr, const fallible_t& aFallible) { // |aStr| could be sharable. We need to check its flags to know how to // deal with it. @@ -434,7 +454,7 @@ nsTSubstring_CharT::Assign(const self_type& aStr, const fallible_t& aFallible) if (!aStr.mLength) { Truncate(); - mDataFlags |= aStr.mDataFlags & DataFlags::VOIDED; + this->mDataFlags |= aStr.mDataFlags & DataFlags::VOIDED; return true; } @@ -444,13 +464,13 @@ nsTSubstring_CharT::Assign(const self_type& aStr, const fallible_t& aFallible) // |aStr| should be null-terminated NS_ASSERTION(aStr.mDataFlags & DataFlags::TERMINATED, "shared, but not terminated"); - ::ReleaseData(mData, mDataFlags); + ::ReleaseData(this->mData, this->mDataFlags); SetData(aStr.mData, aStr.mLength, DataFlags::TERMINATED | DataFlags::SHARED); - // get an owning reference to the mData - nsStringBuffer::FromData(mData)->AddRef(); + // get an owning reference to the this->mData + nsStringBuffer::FromData(this->mData)->AddRef(); return true; } else if (aStr.mDataFlags & DataFlags::LITERAL) { MOZ_ASSERT(aStr.mDataFlags & DataFlags::TERMINATED, "Unterminated literal"); @@ -463,19 +483,21 @@ nsTSubstring_CharT::Assign(const self_type& aStr, const fallible_t& aFallible) return Assign(aStr.Data(), aStr.Length(), aFallible); } +template void -nsTSubstring_CharT::Assign(const substring_tuple_type& aTuple) +nsTSubstring::Assign(const substring_tuple_type& aTuple) { if (!Assign(aTuple, mozilla::fallible)) { AllocFailed(aTuple.Length()); } } +template bool -nsTSubstring_CharT::Assign(const substring_tuple_type& aTuple, - const fallible_t& aFallible) +nsTSubstring::Assign(const substring_tuple_type& aTuple, + const fallible_t& aFallible) { - if (aTuple.IsDependentOn(mData, mData + mLength)) { + if (aTuple.IsDependentOn(this->mData, this->mData + this->mLength)) { // take advantage of sharing here... return Assign(string_type(aTuple), aFallible); } @@ -493,17 +515,18 @@ nsTSubstring_CharT::Assign(const substring_tuple_type& aTuple, ::ReleaseData(oldData, oldFlags); } - aTuple.WriteTo(mData, length); - mData[length] = 0; - mLength = length; + aTuple.WriteTo(this->mData, length); + this->mData[length] = 0; + this->mLength = length; return true; } +template void -nsTSubstring_CharT::Adopt(char_type* aData, size_type aLength) +nsTSubstring::Adopt(char_type* aData, size_type aLength) { if (aData) { - ::ReleaseData(mData, mDataFlags); + ::ReleaseData(this->mData, this->mDataFlags); if (aLength == size_type(-1)) { aLength = char_traits::length(aData); @@ -516,7 +539,7 @@ nsTSubstring_CharT::Adopt(char_type* aData, size_type aLength) STRING_STAT_INCREMENT(Adopt); // Treat this as construction of a "StringAdopt" object for leak // tracking purposes. - MOZ_LOG_CTOR(mData, "StringAdopt", 1); + MOZ_LOG_CTOR(this->mData, "StringAdopt", 1); } else { SetIsVoid(true); } @@ -524,47 +547,51 @@ nsTSubstring_CharT::Adopt(char_type* aData, size_type aLength) // This version of Replace is optimized for single-character replacement. +template void -nsTSubstring_CharT::Replace(index_type aCutStart, size_type aCutLength, - char_type aChar) +nsTSubstring::Replace(index_type aCutStart, size_type aCutLength, + char_type aChar) { - aCutStart = XPCOM_MIN(aCutStart, Length()); + aCutStart = XPCOM_MIN(aCutStart, this->Length()); if (ReplacePrep(aCutStart, aCutLength, 1)) { - mData[aCutStart] = aChar; + this->mData[aCutStart] = aChar; } } +template bool -nsTSubstring_CharT::Replace(index_type aCutStart, size_type aCutLength, - char_type aChar, - const fallible_t&) +nsTSubstring::Replace(index_type aCutStart, size_type aCutLength, + char_type aChar, + const fallible_t&) { - aCutStart = XPCOM_MIN(aCutStart, Length()); + aCutStart = XPCOM_MIN(aCutStart, this->Length()); if (!ReplacePrep(aCutStart, aCutLength, 1)) { return false; } - mData[aCutStart] = aChar; + this->mData[aCutStart] = aChar; return true; } +template void -nsTSubstring_CharT::Replace(index_type aCutStart, size_type aCutLength, - const char_type* aData, size_type aLength) +nsTSubstring::Replace(index_type aCutStart, size_type aCutLength, + const char_type* aData, size_type aLength) { if (!Replace(aCutStart, aCutLength, aData, aLength, mozilla::fallible)) { - AllocFailed(Length() - aCutLength + 1); + AllocFailed(this->Length() - aCutLength + 1); } } +template bool -nsTSubstring_CharT::Replace(index_type aCutStart, size_type aCutLength, - const char_type* aData, size_type aLength, - const fallible_t& aFallible) +nsTSubstring::Replace(index_type aCutStart, size_type aCutLength, + const char_type* aData, size_type aLength, + const fallible_t& aFallible) { // unfortunately, some callers pass null :-( if (!aData) { @@ -574,13 +601,13 @@ nsTSubstring_CharT::Replace(index_type aCutStart, size_type aCutLength, aLength = char_traits::length(aData); } - if (IsDependentOn(aData, aData + aLength)) { - nsTAutoString_CharT temp(aData, aLength); + if (this->IsDependentOn(aData, aData + aLength)) { + nsTAutoString temp(aData, aLength); return Replace(aCutStart, aCutLength, temp, aFallible); } } - aCutStart = XPCOM_MIN(aCutStart, Length()); + aCutStart = XPCOM_MIN(aCutStart, this->Length()); bool ok = ReplacePrep(aCutStart, aCutLength, aLength); if (!ok) { @@ -588,25 +615,27 @@ nsTSubstring_CharT::Replace(index_type aCutStart, size_type aCutLength, } if (aLength > 0) { - char_traits::copy(mData + aCutStart, aData, aLength); + char_traits::copy(this->mData + aCutStart, aData, aLength); } return true; } +template void -nsTSubstring_CharT::ReplaceASCII(index_type aCutStart, size_type aCutLength, - const char* aData, size_type aLength) +nsTSubstring::ReplaceASCII(index_type aCutStart, size_type aCutLength, + const char* aData, size_type aLength) { if (!ReplaceASCII(aCutStart, aCutLength, aData, aLength, mozilla::fallible)) { - AllocFailed(Length() - aCutLength + 1); + AllocFailed(this->Length() - aCutLength + 1); } } +template bool -nsTSubstring_CharT::ReplaceASCII(index_type aCutStart, size_type aCutLength, - const char* aData, size_type aLength, - const fallible_t& aFallible) +nsTSubstring::ReplaceASCII(index_type aCutStart, size_type aCutLength, + const char* aData, size_type aLength, + const fallible_t& aFallible) { if (aLength == size_type(-1)) { aLength = strlen(aData); @@ -615,13 +644,13 @@ nsTSubstring_CharT::ReplaceASCII(index_type aCutStart, size_type aCutLength, // A Unicode string can't depend on an ASCII string buffer, // so this dependence check only applies to CStrings. #ifdef CharT_is_char - if (IsDependentOn(aData, aData + aLength)) { + if (this->IsDependentOn(aData, aData + aLength)) { nsTAutoString_CharT temp(aData, aLength); return Replace(aCutStart, aCutLength, temp, aFallible); } #endif - aCutStart = XPCOM_MIN(aCutStart, Length()); + aCutStart = XPCOM_MIN(aCutStart, this->Length()); bool ok = ReplacePrep(aCutStart, aCutLength, aLength); if (!ok) { @@ -629,60 +658,64 @@ nsTSubstring_CharT::ReplaceASCII(index_type aCutStart, size_type aCutLength, } if (aLength > 0) { - char_traits::copyASCII(mData + aCutStart, aData, aLength); + char_traits::copyASCII(this->mData + aCutStart, aData, aLength); } return true; } +template void -nsTSubstring_CharT::Replace(index_type aCutStart, size_type aCutLength, - const substring_tuple_type& aTuple) +nsTSubstring::Replace(index_type aCutStart, size_type aCutLength, + const substring_tuple_type& aTuple) { - if (aTuple.IsDependentOn(mData, mData + mLength)) { - nsTAutoString_CharT temp(aTuple); + if (aTuple.IsDependentOn(this->mData, this->mData + this->mLength)) { + nsTAutoString temp(aTuple); Replace(aCutStart, aCutLength, temp); return; } size_type length = aTuple.Length(); - aCutStart = XPCOM_MIN(aCutStart, Length()); + aCutStart = XPCOM_MIN(aCutStart, this->Length()); if (ReplacePrep(aCutStart, aCutLength, length) && length > 0) { - aTuple.WriteTo(mData + aCutStart, length); + aTuple.WriteTo(this->mData + aCutStart, length); } } +template void -nsTSubstring_CharT::ReplaceLiteral(index_type aCutStart, size_type aCutLength, - const char_type* aData, size_type aLength) +nsTSubstring::ReplaceLiteral(index_type aCutStart, size_type aCutLength, + const char_type* aData, size_type aLength) { - aCutStart = XPCOM_MIN(aCutStart, Length()); + aCutStart = XPCOM_MIN(aCutStart, this->Length()); - if (!aCutStart && aCutLength == Length()) { + if (!aCutStart && aCutLength == this->Length()) { AssignLiteral(aData, aLength); } else if (ReplacePrep(aCutStart, aCutLength, aLength) && aLength > 0) { - char_traits::copy(mData + aCutStart, aData, aLength); + char_traits::copy(this->mData + aCutStart, aData, aLength); } } +template void -nsTSubstring_CharT::SetCapacity(size_type aCapacity) +nsTSubstring::SetCapacity(size_type aCapacity) { if (!SetCapacity(aCapacity, mozilla::fallible)) { AllocFailed(aCapacity); } } +template bool -nsTSubstring_CharT::SetCapacity(size_type aCapacity, const fallible_t&) +nsTSubstring::SetCapacity(size_type aCapacity, const fallible_t&) { // capacity does not include room for the terminating null char // if our capacity is reduced to zero, then free our buffer. if (aCapacity == 0) { - ::ReleaseData(mData, mDataFlags); + ::ReleaseData(this->mData, this->mDataFlags); SetToEmptyBuffer(); return true; } @@ -694,179 +727,196 @@ nsTSubstring_CharT::SetCapacity(size_type aCapacity, const fallible_t&) } // compute new string length - size_type newLen = XPCOM_MIN(mLength, aCapacity); + size_type newLen = XPCOM_MIN(this->mLength, aCapacity); if (oldData) { // preserve old data - if (mLength > 0) { - char_traits::copy(mData, oldData, newLen); + if (this->mLength > 0) { + char_traits::copy(this->mData, oldData, newLen); } ::ReleaseData(oldData, oldFlags); } - // adjust mLength if our buffer shrunk down in size - if (newLen < mLength) { - mLength = newLen; + // adjust this->mLength if our buffer shrunk down in size + if (newLen < this->mLength) { + this->mLength = newLen; } // always null-terminate here, even if the buffer got longer. this is // for backwards compat with the old string implementation. - mData[aCapacity] = char_type(0); + this->mData[aCapacity] = char_type(0); return true; } +template void -nsTSubstring_CharT::SetLength(size_type aLength) +nsTSubstring::SetLength(size_type aLength) { SetCapacity(aLength); - mLength = aLength; + this->mLength = aLength; } +template bool -nsTSubstring_CharT::SetLength(size_type aLength, const fallible_t& aFallible) +nsTSubstring::SetLength(size_type aLength, const fallible_t& aFallible) { if (!SetCapacity(aLength, aFallible)) { return false; } - mLength = aLength; + this->mLength = aLength; return true; } +template void -nsTSubstring_CharT::SetIsVoid(bool aVal) +nsTSubstring::SetIsVoid(bool aVal) { if (aVal) { Truncate(); - mDataFlags |= DataFlags::VOIDED; + this->mDataFlags |= DataFlags::VOIDED; } else { - mDataFlags &= ~DataFlags::VOIDED; + this->mDataFlags &= ~DataFlags::VOIDED; } } namespace mozilla { namespace detail { -nsTStringRepr_CharT::char_type -nsTStringRepr_CharT::First() const +template +typename nsTStringRepr::char_type +nsTStringRepr::First() const { - MOZ_RELEASE_ASSERT(mLength > 0, "|First()| called on an empty string"); - return mData[0]; + MOZ_RELEASE_ASSERT(this->mLength > 0, "|First()| called on an empty string"); + return this->mData[0]; } -nsTStringRepr_CharT::char_type -nsTStringRepr_CharT::Last() const +template +typename nsTStringRepr::char_type +nsTStringRepr::Last() const { - MOZ_RELEASE_ASSERT(mLength > 0, "|Last()| called on an empty string"); - return mData[mLength - 1]; + MOZ_RELEASE_ASSERT(this->mLength > 0, "|Last()| called on an empty string"); + return this->mData[this->mLength - 1]; } +template bool -nsTStringRepr_CharT::Equals(const self_type& aStr) const +nsTStringRepr::Equals(const self_type& aStr) const { - return mLength == aStr.mLength && - char_traits::compare(mData, aStr.mData, mLength) == 0; + return this->mLength == aStr.mLength && + char_traits::compare(this->mData, aStr.mData, this->mLength) == 0; } +template bool -nsTStringRepr_CharT::Equals(const self_type& aStr, - const comparator_type& aComp) const +nsTStringRepr::Equals(const self_type& aStr, + const comparator_type& aComp) const { - return mLength == aStr.mLength && - aComp(mData, aStr.mData, mLength, aStr.mLength) == 0; + return this->mLength == aStr.mLength && + aComp(this->mData, aStr.mData, this->mLength, aStr.mLength) == 0; } +template bool -nsTStringRepr_CharT::Equals(const substring_tuple_type& aTuple) const +nsTStringRepr::Equals(const substring_tuple_type& aTuple) const { return Equals(substring_type(aTuple)); } +template bool -nsTStringRepr_CharT::Equals(const substring_tuple_type& aTuple, - const comparator_type& aComp) const +nsTStringRepr::Equals(const substring_tuple_type& aTuple, + const comparator_type& aComp) const { return Equals(substring_type(aTuple), aComp); } +template bool -nsTStringRepr_CharT::Equals(const char_type* aData) const +nsTStringRepr::Equals(const char_type* aData) const { // unfortunately, some callers pass null :-( if (!aData) { NS_NOTREACHED("null data pointer"); - return mLength == 0; + return this->mLength == 0; } // XXX avoid length calculation? size_type length = char_traits::length(aData); - return mLength == length && - char_traits::compare(mData, aData, mLength) == 0; + return this->mLength == length && + char_traits::compare(this->mData, aData, this->mLength) == 0; } +template bool -nsTStringRepr_CharT::Equals(const char_type* aData, - const comparator_type& aComp) const +nsTStringRepr::Equals(const char_type* aData, + const comparator_type& aComp) const { // unfortunately, some callers pass null :-( if (!aData) { NS_NOTREACHED("null data pointer"); - return mLength == 0; + return this->mLength == 0; } // XXX avoid length calculation? size_type length = char_traits::length(aData); - return mLength == length && aComp(mData, aData, mLength, length) == 0; + return this->mLength == length && aComp(this->mData, aData, this->mLength, length) == 0; } +template bool -nsTStringRepr_CharT::EqualsASCII(const char* aData, size_type aLen) const +nsTStringRepr::EqualsASCII(const char* aData, size_type aLen) const { - return mLength == aLen && - char_traits::compareASCII(mData, aData, aLen) == 0; + return this->mLength == aLen && + char_traits::compareASCII(this->mData, aData, aLen) == 0; } +template bool -nsTStringRepr_CharT::EqualsASCII(const char* aData) const +nsTStringRepr::EqualsASCII(const char* aData) const { - return char_traits::compareASCIINullTerminated(mData, mLength, aData) == 0; + return char_traits::compareASCIINullTerminated(this->mData, this->mLength, aData) == 0; } +template bool -nsTStringRepr_CharT::LowerCaseEqualsASCII(const char* aData, - size_type aLen) const +nsTStringRepr::LowerCaseEqualsASCII(const char* aData, + size_type aLen) const { - return mLength == aLen && - char_traits::compareLowerCaseToASCII(mData, aData, aLen) == 0; + return this->mLength == aLen && + char_traits::compareLowerCaseToASCII(this->mData, aData, aLen) == 0; } +template bool -nsTStringRepr_CharT::LowerCaseEqualsASCII(const char* aData) const +nsTStringRepr::LowerCaseEqualsASCII(const char* aData) const { - return char_traits::compareLowerCaseToASCIINullTerminated(mData, - mLength, + return char_traits::compareLowerCaseToASCIINullTerminated(this->mData, + this->mLength, aData) == 0; } -nsTStringRepr_CharT::size_type -nsTStringRepr_CharT::CountChar(char_type aChar) const +template +typename nsTStringRepr::size_type +nsTStringRepr::CountChar(char_type aChar) const { - const char_type* start = mData; - const char_type* end = mData + mLength; + const char_type* start = this->mData; + const char_type* end = this->mData + this->mLength; return NS_COUNT(start, end, aChar); } +template int32_t -nsTStringRepr_CharT::FindChar(char_type aChar, index_type aOffset) const +nsTStringRepr::FindChar(char_type aChar, index_type aOffset) const { - if (aOffset < mLength) { - const char_type* result = char_traits::find(mData + aOffset, - mLength - aOffset, aChar); + if (aOffset < this->mLength) { + const char_type* result = char_traits::find(this->mData + aOffset, + this->mLength - aOffset, aChar); if (result) { - return result - mData; + return result - this->mData; } } return -1; @@ -875,22 +925,23 @@ nsTStringRepr_CharT::FindChar(char_type aChar, index_type aOffset) const } // namespace detail } // namespace mozilla +template void -nsTSubstring_CharT::StripChar(char_type aChar) +nsTSubstring::StripChar(char_type aChar) { - if (mLength == 0) { + if (this->mLength == 0) { return; } if (!EnsureMutable()) { // XXX do this lazily? - AllocFailed(mLength); + AllocFailed(this->mLength); } // XXX(darin): this code should defer writing until necessary. - char_type* to = mData; - char_type* from = mData; - char_type* end = mData + mLength; + char_type* to = this->mData; + char_type* from = this->mData; + char_type* end = this->mData + this->mLength; while (from < end) { char_type theChar = *from++; @@ -899,25 +950,26 @@ nsTSubstring_CharT::StripChar(char_type aChar) } } *to = char_type(0); // add the null - mLength = to - mData; + this->mLength = to - this->mData; } +template void -nsTSubstring_CharT::StripChars(const char_type* aChars) +nsTSubstring::StripChars(const char_type* aChars) { - if (mLength == 0) { + if (this->mLength == 0) { return; } if (!EnsureMutable()) { // XXX do this lazily? - AllocFailed(mLength); + AllocFailed(this->mLength); } // XXX(darin): this code should defer writing until necessary. - char_type* to = mData; - char_type* from = mData; - char_type* end = mData + mLength; + char_type* to = this->mData; + char_type* from = this->mData; + char_type* end = this->mData + this->mLength; while (from < end) { char_type theChar = *from++; @@ -931,23 +983,24 @@ nsTSubstring_CharT::StripChars(const char_type* aChars) } } *to = char_type(0); // add the null - mLength = to - mData; + this->mLength = to - this->mData; } +template void -nsTSubstring_CharT::StripTaggedASCII(const ASCIIMaskArray& aToStrip) +nsTSubstring::StripTaggedASCII(const ASCIIMaskArray& aToStrip) { - if (mLength == 0) { + if (this->mLength == 0) { return; } if (!EnsureMutable()) { - AllocFailed(mLength); + AllocFailed(this->mLength); } - char_type* to = mData; - char_type* from = mData; - char_type* end = mData + mLength; + char_type* to = this->mData; + char_type* from = this->mData; + char_type* end = this->mData + this->mLength; while (from < end) { uint32_t theChar = (uint32_t)*from++; @@ -959,11 +1012,12 @@ nsTSubstring_CharT::StripTaggedASCII(const ASCIIMaskArray& aToStrip) } } *to = char_type(0); // add the null - mLength = to - mData; + this->mLength = to - this->mData; } +template void -nsTSubstring_CharT::StripCRLF() +nsTSubstring::StripCRLF() { // Expanding this call to copy the code from StripTaggedASCII // instead of just calling it does somewhat help with performance @@ -971,9 +1025,10 @@ nsTSubstring_CharT::StripCRLF() StripTaggedASCII(mozilla::ASCIIMask::MaskCRLF()); } -struct MOZ_STACK_CLASS PrintfAppend_CharT : public mozilla::PrintfTarget +template +struct MOZ_STACK_CLASS PrintfAppend : public mozilla::PrintfTarget { - explicit PrintfAppend_CharT(nsTSubstring_CharT* aString) + explicit PrintfAppend(nsTSubstring* aString) : mString(aString) { } @@ -989,13 +1044,14 @@ struct MOZ_STACK_CLASS PrintfAppend_CharT : public mozilla::PrintfTarget private: - nsTSubstring_CharT* mString; + nsTSubstring* mString; }; +template void -nsTSubstring_CharT::AppendPrintf(const char* aFormat, ...) +nsTSubstring::AppendPrintf(const char* aFormat, ...) { - PrintfAppend_CharT appender(this); + PrintfAppend appender(this); va_list ap; va_start(ap, aFormat); bool r = appender.vprint(aFormat, ap); @@ -1005,18 +1061,17 @@ nsTSubstring_CharT::AppendPrintf(const char* aFormat, ...) va_end(ap); } +template void -nsTSubstring_CharT::AppendPrintf(const char* aFormat, va_list aAp) +nsTSubstring::AppendPrintf(const char* aFormat, va_list aAp) { - PrintfAppend_CharT appender(this); + PrintfAppend appender(this); bool r = appender.vprint(aFormat, aAp); if (!r) { MOZ_CRASH("Allocation or other failure in PrintfTarget::print"); } } -/* hack to make sure we define FormatWithoutTrailingZeros only once */ -#ifdef CharT_is_PRUnichar // Returns the length of the formatted aDouble in aBuf. static int FormatWithoutTrailingZeros(char (&aBuf)[40], double aDouble, @@ -1087,80 +1142,86 @@ FormatWithoutTrailingZeros(char (&aBuf)[40], double aDouble, return length; } -#endif /* CharT_is_PRUnichar */ +template void -nsTSubstring_CharT::AppendFloat(float aFloat) +nsTSubstring::AppendFloat(float aFloat) { char buf[40]; int length = FormatWithoutTrailingZeros(buf, aFloat, 6); AppendASCII(buf, length); } +template void -nsTSubstring_CharT::AppendFloat(double aFloat) +nsTSubstring::AppendFloat(double aFloat) { char buf[40]; int length = FormatWithoutTrailingZeros(buf, aFloat, 15); AppendASCII(buf, length); } +template size_t -nsTSubstring_CharT::SizeOfExcludingThisIfUnshared( +nsTSubstring::SizeOfExcludingThisIfUnshared( mozilla::MallocSizeOf aMallocSizeOf) const { - if (mDataFlags & DataFlags::SHARED) { - return nsStringBuffer::FromData(mData)-> + if (this->mDataFlags & DataFlags::SHARED) { + return nsStringBuffer::FromData(this->mData)-> SizeOfIncludingThisIfUnshared(aMallocSizeOf); } - if (mDataFlags & DataFlags::OWNED) { - return aMallocSizeOf(mData); + if (this->mDataFlags & DataFlags::OWNED) { + return aMallocSizeOf(this->mData); } // If we reach here, exactly one of the following must be true: - // - DataFlags::VOIDED is set, and mData points to sEmptyBuffer; - // - DataFlags::FIXED is set, and mData points to a buffer within a string + // - DataFlags::VOIDED is set, and this->mData points to sEmptyBuffer; + // - DataFlags::FIXED is set, and this->mData points to a buffer within a string // object (e.g. nsAutoString); - // - None of DataFlags::SHARED, DataFlags::OWNED, DataFlags::FIXED is set, and mData points to a buffer + // - None of DataFlags::SHARED, DataFlags::OWNED, DataFlags::FIXED is set, and this->mData points to a buffer // owned by something else. // // In all three cases, we don't measure it. return 0; } +template size_t -nsTSubstring_CharT::SizeOfExcludingThisEvenIfShared( +nsTSubstring::SizeOfExcludingThisEvenIfShared( mozilla::MallocSizeOf aMallocSizeOf) const { // This is identical to SizeOfExcludingThisIfUnshared except for the // DataFlags::SHARED case. - if (mDataFlags & DataFlags::SHARED) { - return nsStringBuffer::FromData(mData)-> + if (this->mDataFlags & DataFlags::SHARED) { + return nsStringBuffer::FromData(this->mData)-> SizeOfIncludingThisEvenIfShared(aMallocSizeOf); } - if (mDataFlags & DataFlags::OWNED) { - return aMallocSizeOf(mData); + if (this->mDataFlags & DataFlags::OWNED) { + return aMallocSizeOf(this->mData); } return 0; } +template size_t -nsTSubstring_CharT::SizeOfIncludingThisIfUnshared( +nsTSubstring::SizeOfIncludingThisIfUnshared( mozilla::MallocSizeOf aMallocSizeOf) const { return aMallocSizeOf(this) + SizeOfExcludingThisIfUnshared(aMallocSizeOf); } +template size_t -nsTSubstring_CharT::SizeOfIncludingThisEvenIfShared( +nsTSubstring::SizeOfIncludingThisEvenIfShared( mozilla::MallocSizeOf aMallocSizeOf) const { return aMallocSizeOf(this) + SizeOfExcludingThisEvenIfShared(aMallocSizeOf); } +template inline -nsTSubstringSplitter_CharT::nsTSubstringSplitter_CharT( - const nsTSubstring_CharT* aStr, char_type aDelim) +nsTSubstringSplitter::nsTSubstringSplitter( + const nsTSubstring* aStr, char_type aDelim) : mStr(aStr) , mArray(nullptr) , mDelim(aDelim) @@ -1172,7 +1233,7 @@ nsTSubstringSplitter_CharT::nsTSubstringSplitter_CharT( size_type delimCount = mStr->CountChar(aDelim); mArraySize = delimCount + 1; - mArray.reset(new nsTDependentSubstring_CharT[mArraySize]); + mArray.reset(new nsTDependentSubstring[mArraySize]); size_t seenParts = 0; size_type start = 0; @@ -1191,14 +1252,16 @@ nsTSubstringSplitter_CharT::nsTSubstringSplitter_CharT( } while (start < mStr->Length()); } -nsTSubstringSplitter_CharT -nsTSubstring_CharT::Split(const char_type aChar) const +template +nsTSubstringSplitter +nsTSubstring::Split(const char_type aChar) const { - return nsTSubstringSplitter_CharT(this, aChar); + return nsTSubstringSplitter(this, aChar); } -const nsTDependentSubstring_CharT& -nsTSubstringSplitter_CharT::nsTSubstringSplit_Iter::operator* () const +template +const nsTDependentSubstring& +nsTSubstringSplitter::nsTSubstringSplit_Iter::operator* () const { return mObj.Get(mPos); } diff --git a/xpcom/string/nsTSubstring.h b/xpcom/string/nsTSubstring.h index c9711df0cc87..85f44cfa7e1a 100644 --- a/xpcom/string/nsTSubstring.h +++ b/xpcom/string/nsTSubstring.h @@ -5,6 +5,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // IWYU pragma: private, include "nsString.h" +#ifndef nsTSubstring_h +#define nsTSubstring_h + #include "mozilla/Casting.h" #include "mozilla/IntegerPrintfMacros.h" #include "mozilla/UniquePtr.h" @@ -12,317 +15,14 @@ #include "mozilla/IntegerTypeTraits.h" #include "mozilla/Span.h" +#include "nsTStringRepr.h" + #ifndef MOZILLA_INTERNAL_API #error "Using XPCOM strings is limited to code linked into libxul." #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 override; -}; - -class nsTSubstringSplitter_CharT; - -namespace mozilla { -namespace detail { - -/** - * nsTStringRepr defines a string's memory layout and some accessor methods. - * This class exists so that nsTLiteralString can avoid inheriting - * nsTSubstring's destructor. All methods on this class must be const because - * literal strings are not writable. - * - * This class is an implementation detail and should not be instantiated - * directly, nor used in any way outside of the string code itself. It is - * buried in a namespace to discourage its use in function parameters. - * If you need to take a parameter, use [const] ns[C]Substring&. - * If you need to instantiate a string, use ns[C]String or descendents. - * - * NAMES: - * nsStringRepr for wide characters - * nsCStringRepr for narrow characters - * - */ -class nsTStringRepr_CharT -{ -public: - typedef mozilla::fallible_t fallible_t; - - typedef CharT char_type; - - typedef nsCharTraits char_traits; - typedef char_traits::incompatible_char_type incompatible_char_type; - - typedef nsTStringRepr_CharT self_type; - typedef self_type base_string_type; - - typedef nsTSubstring_CharT substring_type; - typedef nsTSubstringTuple_CharT substring_tuple_type; - typedef nsTString_CharT string_type; - - typedef nsReadingIterator const_iterator; - typedef nsWritingIterator iterator; - - typedef nsTStringComparator_CharT comparator_type; - - typedef char_type* char_iterator; - typedef const char_type* const_char_iterator; - - typedef uint32_t index_type; - typedef uint32_t size_type; - - // These are only for internal use within the string classes: - typedef StringDataFlags DataFlags; - typedef StringClassFlags ClassFlags; - - /** - * 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; - } - - /** - * 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; - } - - DataFlags GetDataFlags() const - { - return mDataFlags; - } - - bool IsEmpty() const - { - return mLength == 0; - } - - bool IsLiteral() const - { - return !!(mDataFlags & DataFlags::LITERAL); - } - - bool IsVoid() const - { - return !!(mDataFlags & DataFlags::VOIDED); - } - - bool IsTerminated() const - { - return !!(mDataFlags & DataFlags::TERMINATED); - } - - 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; - - char_type Last() const; - - size_type NS_FASTCALL CountChar(char_type) const; - int32_t NS_FASTCALL FindChar(char_type, index_type aOffset = 0) const; - - inline bool Contains(char_type aChar) const - { - return FindChar(aChar) != kNotFound; - } - - /** - * 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 substring_tuple_type& aTuple) const; - bool NS_FASTCALL Equals(const substring_tuple_type& aTuple, - const comparator_type& aComp) 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(aData)); - } - bool NS_FASTCALL Equals(char16ptr_t aData, const comparator_type& aComp) const - { - return Equals(static_cast(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 - 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 - inline bool LowerCaseEqualsLiteral(const char (&aStr)[N]) const - { - return LowerCaseEqualsASCII(aStr, N - 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); - } - -protected: - nsTStringRepr_CharT() = delete; // Never instantiate directly - - constexpr - nsTStringRepr_CharT(char_type* aData, size_type aLength, - DataFlags aDataFlags, ClassFlags aClassFlags) - : mData(aData) - , mLength(aLength) - , mDataFlags(aDataFlags) - , mClassFlags(aClassFlags) - { - } - - char_type* mData; - size_type mLength; - DataFlags mDataFlags; - ClassFlags const mClassFlags; -}; - -} // namespace detail -} // namespace mozilla +template class nsTSubstringSplitter; +template class nsTString; /** * nsTSubstring is an abstract string class. From an API perspective, this @@ -336,13 +36,45 @@ protected: * nsACString for narrow characters * */ -class nsTSubstring_CharT : public mozilla::detail::nsTStringRepr_CharT +template +class nsTSubstring : public mozilla::detail::nsTStringRepr { public: - typedef nsTSubstring_CharT self_type; + typedef nsTSubstring self_type; + + typedef nsTString string_type; + + typedef typename mozilla::detail::nsTStringRepr base_string_type; + typedef typename base_string_type::substring_type substring_type; + + typedef typename base_string_type::fallible_t fallible_t; + + typedef typename base_string_type::char_type char_type; + typedef typename base_string_type::char_traits char_traits; + typedef typename base_string_type::incompatible_char_type incompatible_char_type; + + typedef typename base_string_type::substring_tuple_type substring_tuple_type; + + typedef typename base_string_type::const_iterator const_iterator; + typedef typename base_string_type::iterator iterator; + + typedef typename base_string_type::comparator_type comparator_type; + + typedef typename base_string_type::char_iterator char_iterator; + typedef typename base_string_type::const_char_iterator const_char_iterator; + + typedef typename base_string_type::index_type index_type; + typedef typename base_string_type::size_type size_type; + + // These are only for internal use within the string classes: + typedef typename base_string_type::DataFlags DataFlags; + typedef typename base_string_type::ClassFlags ClassFlags; + + using typename base_string_type::IsChar; + using typename base_string_type::IsChar16; // this acts like a virtual destructor - ~nsTSubstring_CharT() + ~nsTSubstring() { Finalize(); } @@ -354,29 +86,29 @@ public: char_iterator BeginWriting() { if (!EnsureMutable()) { - AllocFailed(mLength); + AllocFailed(base_string_type::mLength); } - return mData; + return base_string_type::mData; } char_iterator BeginWriting(const fallible_t&) { - return EnsureMutable() ? mData : char_iterator(0); + return EnsureMutable() ? base_string_type::mData : char_iterator(0); } char_iterator EndWriting() { if (!EnsureMutable()) { - AllocFailed(mLength); + AllocFailed(base_string_type::mLength); } - return mData + mLength; + return base_string_type::mData + base_string_type::mLength; } char_iterator EndWriting(const fallible_t&) { - return EnsureMutable() ? (mData + mLength) : char_iterator(0); + return EnsureMutable() ? (base_string_type::mData + base_string_type::mLength) : char_iterator(0); } char_iterator& BeginWriting(char_iterator& aIter) @@ -407,7 +139,7 @@ public: { char_type* data = BeginWriting(); aIter.mStart = data; - aIter.mEnd = data + mLength; + aIter.mEnd = data + base_string_type::mLength; aIter.mPosition = aIter.mStart; return aIter; } @@ -416,7 +148,7 @@ public: { char_type* data = BeginWriting(); aIter.mStart = data; - aIter.mEnd = data + mLength; + aIter.mEnd = data + base_string_type::mLength; aIter.mPosition = aIter.mEnd; return aIter; } @@ -443,17 +175,20 @@ public: MOZ_MUST_USE bool NS_FASTCALL Assign(const substring_tuple_type&, const fallible_t&); -#if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER) +#if defined(MOZ_USE_CHAR16_WRAPPER) + template void Assign(char16ptr_t aData) { Assign(static_cast(aData)); } + template void Assign(char16ptr_t aData, size_type aLength) { Assign(static_cast(aData), aLength); } + template MOZ_MUST_USE bool Assign(char16ptr_t aData, size_type aLength, const fallible_t& aFallible) { @@ -490,13 +225,12 @@ public: { AssignLiteral(aStr, N - 1); } -#ifdef CharT_is_PRUnichar - template - void AssignLiteral(const char (&aStr)[N]) + + template + void AssignLiteral(const incompatible_char_type (&aStr)[N]) { AssignASCII(aStr, N - 1); } -#endif self_type& operator=(char_type aChar) { @@ -508,7 +242,8 @@ public: Assign(aData); return *this; } -#if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER) +#if defined(MOZ_USE_CHAR16_WRAPPER) + template self_type& operator=(char16ptr_t aData) { Assign(aData); @@ -587,23 +322,24 @@ public: void Append(char_type aChar) { - Replace(mLength, 0, aChar); + Replace(base_string_type::mLength, 0, aChar); } MOZ_MUST_USE bool Append(char_type aChar, const fallible_t& aFallible) { - return Replace(mLength, 0, aChar, aFallible); + return Replace(base_string_type::mLength, 0, aChar, aFallible); } void Append(const char_type* aData, size_type aLength = size_type(-1)) { - Replace(mLength, 0, aData, aLength); + Replace(base_string_type::mLength, 0, aData, aLength); } MOZ_MUST_USE bool Append(const char_type* aData, size_type aLength, const fallible_t& aFallible) { - return Replace(mLength, 0, aData, aLength, aFallible); + return Replace(base_string_type::mLength, 0, aData, aLength, aFallible); } -#if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER) +#if defined(MOZ_USE_CHAR16_WRAPPER) + template void Append(char16ptr_t aData, size_type aLength = size_type(-1)) { Append(static_cast(aData), aLength); @@ -612,30 +348,30 @@ public: void Append(const self_type& aStr) { - Replace(mLength, 0, aStr); + Replace(base_string_type::mLength, 0, aStr); } MOZ_MUST_USE bool Append(const self_type& aStr, const fallible_t& aFallible) { - return Replace(mLength, 0, aStr, aFallible); + return Replace(base_string_type::mLength, 0, aStr, aFallible); } void Append(const substring_tuple_type& aTuple) { - Replace(mLength, 0, aTuple); + Replace(base_string_type::mLength, 0, aTuple); } void AppendASCII(const char* aData, size_type aLength = size_type(-1)) { - ReplaceASCII(mLength, 0, aData, aLength); + ReplaceASCII(base_string_type::mLength, 0, aData, aLength); } MOZ_MUST_USE bool AppendASCII(const char* aData, const fallible_t& aFallible) { - return ReplaceASCII(mLength, 0, aData, size_type(-1), aFallible); + return ReplaceASCII(base_string_type::mLength, 0, aData, size_type(-1), aFallible); } MOZ_MUST_USE bool AppendASCII(const char* aData, size_type aLength, const fallible_t& aFallible) { - return ReplaceASCII(mLength, 0, aData, aLength, aFallible); + return ReplaceASCII(base_string_type::mLength, 0, aData, aLength, aFallible); } /** @@ -704,21 +440,23 @@ public: template void AppendLiteral(const char_type (&aStr)[N]) { - ReplaceLiteral(mLength, 0, aStr, N - 1); + ReplaceLiteral(base_string_type::mLength, 0, aStr, N - 1); } -#ifdef CharT_is_PRUnichar - template - void AppendLiteral(const char (&aStr)[N]) + + // Only enable for T = char16_t + template + void AppendLiteral(const incompatible_char_type (&aStr)[N]) { AppendASCII(aStr, N - 1); } - template - MOZ_MUST_USE bool AppendLiteral(const char (&aStr)[N], const fallible_t& aFallible) + // Only enable for T = char16_t + template + MOZ_MUST_USE bool + AppendLiteral(const incompatible_char_type (&aStr)[N], const fallible_t& aFallible) { return AppendASCII(aStr, N - 1, aFallible); } -#endif self_type& operator+=(char_type aChar) { @@ -730,7 +468,8 @@ public: Append(aData); return *this; } -#if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER) +#if defined(MOZ_USE_CHAR16_WRAPPER) + template self_type& operator+=(char16ptr_t aData) { Append(aData); @@ -757,7 +496,8 @@ public: { Replace(aPos, 0, aData, aLength); } -#if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER) +#if defined(MOZ_USE_CHAR16_WRAPPER) + template void Insert(char16ptr_t aData, index_type aPos, size_type aLength = size_type(-1)) { @@ -787,7 +527,7 @@ public: Replace(aCutStart, aCutLength, char_traits::sEmptyBuffer, 0); } - nsTSubstringSplitter_CharT Split(const char_type aChar) const; + nsTSubstringSplitter Split(const char_type aChar) const; /** * buffer sizing @@ -810,7 +550,7 @@ public: void Truncate(size_type aNewLength = 0) { - NS_ASSERTION(aNewLength <= mLength, "Truncate cannot make string longer"); + NS_ASSERTION(aNewLength <= base_string_type::mLength, "Truncate cannot make string longer"); SetLength(aNewLength); } @@ -828,8 +568,8 @@ public: */ inline size_type GetData(const char_type** aData) const { - *aData = mData; - return mLength; + *aData = base_string_type::mData; + return base_string_type::mLength; } /** @@ -845,11 +585,11 @@ public: size_type GetMutableData(char_type** aData, size_type aNewLen = size_type(-1)) { if (!EnsureMutable(aNewLen)) { - AllocFailed(aNewLen == size_type(-1) ? mLength : aNewLen); + AllocFailed(aNewLen == size_type(-1) ? base_string_type::mLength : aNewLen); } - *aData = mData; - return mLength; + *aData = base_string_type::mData; + return base_string_type::mLength; } size_type GetMutableData(char_type** aData, size_type aNewLen, const fallible_t&) @@ -859,16 +599,18 @@ public: return 0; } - *aData = mData; - return mLength; + *aData = base_string_type::mData; + return base_string_type::mLength; } -#if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER) +#if defined(MOZ_USE_CHAR16_WRAPPER) + template size_type GetMutableData(wchar_t** aData, size_type aNewLen = size_type(-1)) { return GetMutableData(reinterpret_cast(aData), aNewLen); } + template size_type GetMutableData(wchar_t** aData, size_type aNewLen, const fallible_t& aFallible) { @@ -883,12 +625,12 @@ public: operator mozilla::Span() { - return mozilla::MakeSpan(BeginWriting(), Length()); + return mozilla::MakeSpan(BeginWriting(), base_string_type::Length()); } operator mozilla::Span() const { - return mozilla::MakeSpan(BeginReading(), Length()); + return mozilla::MakeSpan(base_string_type::BeginReading(), base_string_type::Length()); } void Append(mozilla::Span aSpan) @@ -908,19 +650,21 @@ public: return Append(aSpan.Elements(), len, aFallible); } -#if !defined(CharT_is_PRUnichar) + template operator mozilla::Span() { return mozilla::MakeSpan(reinterpret_cast(BeginWriting()), - Length()); + base_string_type::Length()); } + template operator mozilla::Span() const { - return mozilla::MakeSpan(reinterpret_cast(BeginReading()), - Length()); + return mozilla::MakeSpan(reinterpret_cast(base_string_type::BeginReading()), + base_string_type::Length()); } + template void Append(mozilla::Span aSpan) { auto len = aSpan.Length(); @@ -928,6 +672,7 @@ public: Append(reinterpret_cast(aSpan.Elements()), len); } + template MOZ_MUST_USE bool Append(mozilla::Span aSpan, const fallible_t& aFallible) { @@ -938,7 +683,6 @@ public: return Append( reinterpret_cast(aSpan.Elements()), len, aFallible); } -#endif /** * string data is never null, but can be marked void. if true, the @@ -995,7 +739,7 @@ public: */ void ForgetSharedBuffer() { - if (mDataFlags & DataFlags::SHARED) { + if (base_string_type::mDataFlags & DataFlags::SHARED) { SetToEmptyBuffer(); } } @@ -1003,8 +747,8 @@ public: protected: void AssertValid() { - MOZ_ASSERT(!(mClassFlags & ClassFlags::NULL_TERMINATED) || - (mDataFlags & DataFlags::TERMINATED), + MOZ_ASSERT(!(this->mClassFlags & ClassFlags::NULL_TERMINATED) || + (this->mDataFlags & DataFlags::TERMINATED), "String classes whose static type guarantees a null-terminated " "buffer must not be assigned a non-null-terminated buffer."); } @@ -1015,8 +759,8 @@ 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) - : nsTStringRepr_CharT(nullptr, 0, DataFlags(0), ClassFlags(0)) + MOZ_IMPLICIT nsTSubstring(const substring_tuple_type& aTuple) + : base_string_type(nullptr, 0, DataFlags(0), ClassFlags(0)) { AssertValid(); Assign(aTuple); @@ -1038,11 +782,11 @@ public: size_t SizeOfIncludingThisEvenIfShared(mozilla::MallocSizeOf aMallocSizeOf) const; - template + template void NS_ABORT_OOM(T) { struct never {}; // a compiler-friendly way to do static_assert(false) - static_assert(mozilla::IsSame::value, + static_assert(mozilla::IsSame::value, "In string classes, use AllocFailed to account for sizeof(char_type). " "Use the global ::NS_ABORT_OOM if you really have a count of bytes."); } @@ -1055,27 +799,27 @@ public: protected: // default initialization - nsTSubstring_CharT() - : nsTStringRepr_CharT(char_traits::sEmptyBuffer, 0, DataFlags::TERMINATED, - ClassFlags(0)) + nsTSubstring() + : base_string_type(char_traits::sEmptyBuffer, 0, DataFlags::TERMINATED, + ClassFlags(0)) { AssertValid(); } // copy-constructor, constructs as dependent on given object // (NOTE: this is for internal use only) - nsTSubstring_CharT(const self_type& aStr) - : nsTStringRepr_CharT(aStr.mData, aStr.mLength, - aStr.mDataFlags & (DataFlags::TERMINATED | DataFlags::VOIDED), - ClassFlags(0)) + nsTSubstring(const self_type& aStr) + : base_string_type(aStr.base_string_type::mData, aStr.base_string_type::mLength, + aStr.base_string_type::mDataFlags & (DataFlags::TERMINATED | DataFlags::VOIDED), + ClassFlags(0)) { AssertValid(); } // initialization with ClassFlags - explicit nsTSubstring_CharT(ClassFlags aClassFlags) - : nsTStringRepr_CharT(char_traits::sEmptyBuffer, 0, DataFlags::TERMINATED, - aClassFlags) + explicit nsTSubstring(ClassFlags aClassFlags) + : base_string_type(char_traits::sEmptyBuffer, 0, DataFlags::TERMINATED, + aClassFlags) { AssertValid(); } @@ -1083,15 +827,15 @@ protected: /** * allows for direct initialization of a nsTSubstring object. */ - nsTSubstring_CharT(char_type* aData, size_type aLength, - DataFlags aDataFlags, ClassFlags aClassFlags) + nsTSubstring(char_type* aData, size_type aLength, + DataFlags aDataFlags, ClassFlags aClassFlags) // 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 ; #else #undef XPCOM_STRING_CONSTRUCTOR_OUT_OF_LINE - : nsTStringRepr_CharT(aData, aLength, aDataFlags, aClassFlags) + : base_string_type(aData, aLength, aDataFlags, aClassFlags) { AssertValid(); MOZ_RELEASE_ASSERT(CheckCapacity(aLength), "String is too large."); @@ -1100,17 +844,17 @@ protected: void SetToEmptyBuffer() { - mData = char_traits::sEmptyBuffer; - mLength = 0; - mDataFlags = DataFlags::TERMINATED; + base_string_type::mData = char_traits::sEmptyBuffer; + base_string_type::mLength = 0; + base_string_type::mDataFlags = DataFlags::TERMINATED; AssertValid(); } void SetData(char_type* aData, size_type aLength, DataFlags aDataFlags) { - mData = aData; - mLength = aLength; - mDataFlags = aDataFlags; + base_string_type::mData = aData; + base_string_type::mLength = aLength; + base_string_type::mDataFlags = aDataFlags; AssertValid(); } @@ -1213,85 +957,27 @@ public: void NS_FASTCALL AssignLiteral(const char_type* aData, size_type aLength); }; -static_assert(sizeof(nsTSubstring_CharT) == - sizeof(mozilla::detail::nsTStringRepr_CharT), +extern template class nsTSubstring; +extern template class nsTSubstring; + +static_assert(sizeof(nsTSubstring) == + sizeof(mozilla::detail::nsTStringRepr), "Don't add new data fields to nsTSubstring_CharT. " - "Add to nsTStringRepr_CharT instead."); + "Add to nsTStringRepr instead."); -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::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; -} - -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; -} // You should not need to instantiate this class directly. // Use nsTSubstring::Split instead. -class nsTSubstringSplitter_CharT +template +class nsTSubstringSplitter { - typedef nsTSubstring_CharT::size_type size_type; - typedef nsTSubstring_CharT::char_type char_type; + typedef typename nsTSubstring::size_type size_type; + typedef typename nsTSubstring::char_type char_type; class nsTSubstringSplit_Iter { public: - nsTSubstringSplit_Iter(const nsTSubstringSplitter_CharT& aObj, + nsTSubstringSplit_Iter(const nsTSubstringSplitter& aObj, size_type aPos) : mObj(aObj) , mPos(aPos) @@ -1303,7 +989,7 @@ class nsTSubstringSplitter_CharT return mPos != other.mPos; } - const nsTDependentSubstring_CharT& operator*() const; + const nsTDependentSubstring& operator*() const; const nsTSubstringSplit_Iter& operator++() { @@ -1312,18 +998,18 @@ class nsTSubstringSplitter_CharT } private: - const nsTSubstringSplitter_CharT& mObj; + const nsTSubstringSplitter& mObj; size_type mPos; }; private: - const nsTSubstring_CharT* const mStr; - mozilla::UniquePtr mArray; + const nsTSubstring* const mStr; + mozilla::UniquePtr[]> mArray; size_type mArraySize; const char_type mDelim; public: - nsTSubstringSplitter_CharT(const nsTSubstring_CharT* aStr, char_type aDelim); + nsTSubstringSplitter(const nsTSubstring* aStr, char_type aDelim); nsTSubstringSplit_Iter begin() const { @@ -1335,28 +1021,46 @@ public: return nsTSubstringSplit_Iter(*this, mArraySize); } - const nsTDependentSubstring_CharT& Get(const size_type index) const + const nsTDependentSubstring& Get(const size_type index) const { MOZ_ASSERT(index < mArraySize); return mArray[index]; } }; +extern template class nsTSubstringSplitter; +extern template class nsTSubstringSplitter; + /** * Span integration */ namespace mozilla { -inline Span -MakeSpan(nsTSubstring_CharT& aString) +inline Span +MakeSpan(nsTSubstring& aString) { return aString; } -inline Span -MakeSpan(const nsTSubstring_CharT& aString) +inline Span +MakeSpan(const nsTSubstring& aString) { return aString; } +inline Span +MakeSpan(nsTSubstring& aString) +{ + return aString; +} + +inline Span +MakeSpan(const nsTSubstring& aString) +{ + return aString; +} + + } // namespace mozilla + +#endif diff --git a/xpcom/string/nsTSubstringTuple.cpp b/xpcom/string/nsTSubstringTuple.cpp index 721d1b55fab0..92371c21faf6 100644 --- a/xpcom/string/nsTSubstringTuple.cpp +++ b/xpcom/string/nsTSubstringTuple.cpp @@ -10,8 +10,9 @@ * computes the aggregate string length */ -nsTSubstringTuple_CharT::size_type -nsTSubstringTuple_CharT::Length() const +template +typename nsTSubstringTuple::size_type +nsTSubstringTuple::Length() const { mozilla::CheckedInt len; if (mHead) { @@ -32,8 +33,9 @@ nsTSubstringTuple_CharT::Length() const * method. the string written to |aBuf| is not null-terminated. */ +template void -nsTSubstringTuple_CharT::WriteTo(char_type* aBuf, uint32_t aBufLen) const +nsTSubstringTuple::WriteTo(char_type* aBuf, uint32_t aBufLen) const { MOZ_RELEASE_ASSERT(aBufLen >= mFragB->Length(), "buffer too small"); uint32_t headLen = aBufLen - mFragB->Length(); @@ -53,9 +55,10 @@ nsTSubstringTuple_CharT::WriteTo(char_type* aBuf, uint32_t aBufLen) const * the given char sequence. */ +template bool -nsTSubstringTuple_CharT::IsDependentOn(const char_type* aStart, - const char_type* aEnd) const +nsTSubstringTuple::IsDependentOn(const char_type* aStart, + const char_type* aEnd) const { // we aStart with the right-most fragment since it is faster to check. diff --git a/xpcom/string/nsTSubstringTuple.h b/xpcom/string/nsTSubstringTuple.h index 411bf070a1ec..000eebc0dd33 100644 --- a/xpcom/string/nsTSubstringTuple.h +++ b/xpcom/string/nsTSubstringTuple.h @@ -5,8 +5,13 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // IWYU pragma: private, include "nsString.h" +#ifndef nsTSubstringTuple_h +#define nsTSubstringTuple_h + +#include "nsTStringRepr.h" + /** - * nsTSubstringTuple_CharT + * nsTSubstringTuple * * Represents a tuple of string fragments. Built as a recursive binary tree. * It is used to implement the concatenation of two or more string objects. @@ -14,29 +19,30 @@ * NOTE: This class is a private implementation detail and should never be * referenced outside the string code. */ -class nsTSubstringTuple_CharT +template +class nsTSubstringTuple { public: - typedef CharT char_type; - typedef nsCharTraits char_traits; + typedef T char_type; + typedef nsCharTraits char_traits; - typedef nsTSubstringTuple_CharT self_type; - typedef mozilla::detail::nsTStringRepr_CharT base_string_type; - typedef uint32_t size_type; + typedef nsTSubstringTuple self_type; + typedef mozilla::detail::nsTStringRepr base_string_type; + typedef uint32_t size_type; public: - nsTSubstringTuple_CharT(const base_string_type* aStrA, - const base_string_type* aStrB) + nsTSubstringTuple(const base_string_type* aStrA, + const base_string_type* aStrB) : mHead(nullptr) , mFragA(aStrA) , mFragB(aStrB) { } - nsTSubstringTuple_CharT(const self_type& aHead, - const base_string_type* aStrB) + nsTSubstringTuple(const self_type& aHead, + const base_string_type* aStrB) : mHead(&aHead) , mFragA(nullptr) // this fragment is ignored when aHead != nullptr , mFragB(aStrB) @@ -68,16 +74,20 @@ private: const base_string_type* const mFragB; }; -inline const nsTSubstringTuple_CharT -operator+(const nsTSubstringTuple_CharT::base_string_type& aStrA, - const nsTSubstringTuple_CharT::base_string_type& aStrB) +template +inline const nsTSubstringTuple +operator+(const mozilla::detail::nsTStringRepr& aStrA, + const mozilla::detail::nsTStringRepr& aStrB) { - return nsTSubstringTuple_CharT(&aStrA, &aStrB); + return nsTSubstringTuple(&aStrA, &aStrB); } -inline const nsTSubstringTuple_CharT -operator+(const nsTSubstringTuple_CharT& aHead, - const nsTSubstringTuple_CharT::base_string_type& aStrB) +template +inline const nsTSubstringTuple +operator+(const nsTSubstringTuple& aHead, + const mozilla::detail::nsTStringRepr& aStrB) { - return nsTSubstringTuple_CharT(aHead, &aStrB); + return nsTSubstringTuple(aHead, &aStrB); } + +#endif diff --git a/xpcom/string/precompiled_templates.cpp b/xpcom/string/precompiled_templates.cpp new file mode 100644 index 000000000000..f3eb5503f020 --- /dev/null +++ b/xpcom/string/precompiled_templates.cpp @@ -0,0 +1,115 @@ +/* -*- 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/. */ + +#include "nsString.h" + +// This file provides concrete instantiations for externed string template +// classes and functions. + +// ================ +// Template classes +// ================ +template class mozilla::detail::nsTStringRepr; +template class mozilla::detail::nsTStringRepr; + +template class nsTLiteralString; +template class nsTLiteralString; + +template class nsTSubstring; +template class nsTSubstring; + +template class nsTDependentSubstring; +template class nsTDependentSubstring; + +// Note: nsTString is skipped as it's implicitly instantiated by derived +// classes. + +template class nsTFixedString; +template class nsTFixedString; +template class nsTAutoStringN; +template class nsTAutoStringN; + +template class nsTDependentString; +template class nsTDependentString; + +template class nsTPromiseFlatString; +template class nsTPromiseFlatString; + +template class nsTSubstringSplitter; +template class nsTSubstringSplitter; + +template class nsTDefaultStringComparator; +template class nsTDefaultStringComparator; + +// ============================= +// Templated top-level functions +// ============================= + +template +int +Compare(mozilla::detail::nsTStringRepr const&, + mozilla::detail::nsTStringRepr const&, + nsTStringComparator const&); + +template +int +Compare(mozilla::detail::nsTStringRepr const&, + mozilla::detail::nsTStringRepr const&, + nsTStringComparator const&); + +template +nsTDependentSubstring const +Substring(char const*, char const*); + +template +nsTDependentSubstring const +Substring(char16_t const*, char16_t const*); + +// ========================================================= +// Templated member functions that are conditionally enabled +// ========================================================= + +template +int32_t +nsTString::Find(const self_type&, int32_t, int32_t) const; + +template +int32_t +nsTString::Find(const char_type*, int32_t, int32_t) const; + +template +int32_t +nsTString::RFind(const self_type&, int32_t, int32_t) const; + +template +int32_t +nsTString::RFind(const char_type*, int32_t, int32_t) const; + +template +int32_t +nsTString::FindCharInSet(const char*, int32_t) const; + +template +int32_t +nsTString::Compare(const char_type*, bool, int32_t) const; + +template +bool +nsTString::EqualsIgnoreCase(const incompatible_char_type*, + int32_t) const; + +template +bool +nsTString::StripChars(const incompatible_char_type*, + const fallible_t&); + +template +void +nsTString::StripChars(const incompatible_char_type*); + +template +void +nsTString::ReplaceChar(const char*, char16_t); diff --git a/xpcom/string/string-template-def-char.h b/xpcom/string/string-template-def-char.h deleted file mode 100644 index e142e38dc3fb..000000000000 --- a/xpcom/string/string-template-def-char.h +++ /dev/null @@ -1,28 +0,0 @@ -/* -*- 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" - -#define CharT char -#define CharT_is_char 1 -#define nsTAString_IncompatibleCharT nsAString -#define nsTString_CharT nsCString -#define nsTStringRepr_CharT nsCStringRepr -#define nsTFixedString_CharT nsFixedCString -#define nsTAutoStringN_CharT nsAutoCStringN -#define nsTAutoString_CharT nsAutoCString -#define nsTSubstring_CharT nsACString -#define PrintfAppend_CharT PrintfAppend_nsACString -#define nsTSubstringTuple_CharT nsCSubstringTuple -#define nsTStringComparator_CharT nsCStringComparator -#define nsTDefaultStringComparator_CharT nsDefaultCStringComparator -#define nsTDependentString_CharT nsDependentCString -#define nsTDependentSubstring_CharT nsDependentCSubstring -#define nsTLiteralString_CharT nsLiteralCString -#define nsTGetterCopies_CharT nsCGetterCopies -#define nsTPromiseFlatString_CharT nsPromiseFlatCString -#define TPromiseFlatString_CharT PromiseFlatCString -#define nsTSubstringSplitter_CharT nsCSubstringSplitter -#define TNullString_CharT NullCString diff --git a/xpcom/string/string-template-def-unichar.h b/xpcom/string/string-template-def-unichar.h deleted file mode 100644 index a3ba3090a745..000000000000 --- a/xpcom/string/string-template-def-unichar.h +++ /dev/null @@ -1,28 +0,0 @@ -/* -*- 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" - -#define CharT char16_t -#define CharT_is_PRUnichar 1 -#define nsTAString_IncompatibleCharT nsACString -#define nsTString_CharT nsString -#define nsTStringRepr_CharT nsStringRepr -#define nsTFixedString_CharT nsFixedString -#define nsTAutoStringN_CharT nsAutoStringN -#define nsTAutoString_CharT nsAutoString -#define nsTSubstring_CharT nsAString -#define PrintfAppend_CharT PrintfAppend_nsAString -#define nsTSubstringTuple_CharT nsSubstringTuple -#define nsTStringComparator_CharT nsStringComparator -#define nsTDefaultStringComparator_CharT nsDefaultStringComparator -#define nsTDependentString_CharT nsDependentString -#define nsTDependentSubstring_CharT nsDependentSubstring -#define nsTLiteralString_CharT nsLiteralString -#define nsTGetterCopies_CharT nsGetterCopies -#define nsTPromiseFlatString_CharT nsPromiseFlatString -#define TPromiseFlatString_CharT PromiseFlatString -#define nsTSubstringSplitter_CharT nsSubstringSplitter -#define TNullString_CharT NullString diff --git a/xpcom/string/string-template-undef.h b/xpcom/string/string-template-undef.h deleted file mode 100644 index b3cbb6c38eb9..000000000000 --- a/xpcom/string/string-template-undef.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -*- 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" - -#undef CharT -#undef CharT_is_PRUnichar -#undef CharT_is_char -#undef nsTAString_IncompatibleCharT -#undef nsTString_CharT -#undef nsTStringRepr_CharT -#undef nsTFixedString_CharT -#undef nsTAutoStringN_CharT -#undef nsTAutoString_CharT -#undef nsTSubstring_CharT -#undef PrintfAppend_CharT -#undef nsTSubstringTuple_CharT -#undef nsTStringComparator_CharT -#undef nsTDefaultStringComparator_CharT -#undef nsTDependentString_CharT -#undef nsTDependentSubstring_CharT -#undef nsTLiteralString_CharT -#undef nsTGetterCopies_CharT -#undef nsTPromiseFlatString_CharT -#undef TPromiseFlatString_CharT -#undef nsTSubstringSplitter_CharT -#undef TNullString_CharT