/* -*- 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 "mozilla/Char16.h" #include "mozilla/fallible.h" #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 { // This is mainly intended to be used in the context of nsTStrings where // we want to enable a specific function only for a given character class. In // order for this technique to work the member function needs to be templated // on something other than `T`. We keep this in the `mozilla` namespace rather // than `nsTStringRepr` as it's intentionally not dependent on `T`. // // The 'T' at the end of `Char[16]OnlyT` is refering to the `::type` portion // which will only be defined if the character class is correct. This is similar // to `std::enable_if_t` which is available in C++14, but not C++11. // // `CharType` is generally going to be a shadowed type of `T`. // // Example usage of a function that will only be defined if `T` == `char`: // // template // class nsTSubstring : public nsTStringRepr { // template > // int Foo() { return 42; } // }; // // Please note that we had to use a separate type `Q` for this to work. You // will get a semi-decent compiler error if you use `T` directly. template using CharOnlyT = typename std::enable_if::value>::type; template using Char16OnlyT = typename std::enable_if::value>::type; 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 char_type* iterator; typedef nsTStringComparator comparator_type; 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. 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 called with an actual literal string, or // a char array *constant* declared without an explicit size and with an // initializer that is a string literal or is otherwise null-terminated. // Use EqualsASCII for other char array variables. // (Although this method may happen to produce expected results for other // char arrays that have bound one greater than the sequence of interest, // such use is discouraged for reasons of readability and maintainability.) // The template trick to acquire the array bound 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 called with an actual literal string, // or a char array *constant* declared without an explicit size and with an // initializer that is a string literal or is otherwise null-terminated. // Use LowerCaseEqualsASCII for other char array variables. // (Although this method may happen to produce expected results for other // char arrays that have bound one greater than the sequence of interest, // such use is discouraged for reasons of readability and maintainability.) 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 (To avoid relying on Undefined Behavior // from comparing pointers from different allocations (which in // principle gives the optimizer the permission to assume elsewhere // that the pointers are from the same allocation), the comparisons // are done on integers, which merely relies on implementation-defined // behavior of converting pointers to integers. std::less and // std::greater implementations don't actually provide the guarantees // that they should.): return (reinterpret_cast(aStart) < reinterpret_cast(mData + mLength) && reinterpret_cast(aEnd) > reinterpret_cast(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